author | Zhuoyao Zhang <zhuoyao@google.com> | |
Wed, 13 Jun 2018 00:05:50 +0000 (00:05 +0000) | ||
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | |
Wed, 13 Jun 2018 00:05:50 +0000 (00:05 +0000) |
100 files changed:
index 3727966279d36d7b17e2a8a2334cd509c1ebc114..8b83e464412184010dde7b9e37c7931261d957dd 100644 (file)
}
Result Device::analyzeStatus(const char* funcName, int status) {
- if (status != 0) {
- ALOGW("Device %p %s: %s", mDevice, funcName, strerror(-status));
- }
- switch (status) {
- case 0:
- return Result::OK;
- case -EINVAL:
- return Result::INVALID_ARGUMENTS;
- case -ENODATA:
- return Result::INVALID_STATE;
- case -ENODEV:
- return Result::NOT_INITIALIZED;
- case -ENOSYS:
- return Result::NOT_SUPPORTED;
- default:
- return Result::INVALID_STATE;
- }
+ return util::analyzeStatus("Device", funcName, status);
}
void Device::closeInputStream(audio_stream_in_t* stream) {
index 2140885f20b9a0cdfc7675576ddb1775f543ed52..257c8e5f0d88dcc9fac16bded75f0d8ee24523d6 100644 (file)
*/
#include "ParametersUtil.h"
+#include "Util.h"
namespace android {
namespace hardware {
Result ParametersUtil::setParams(const AudioParameter& param) {
int halStatus = halSetParameters(param.toString().string());
- if (halStatus == OK)
- return Result::OK;
- else if (halStatus == -ENOSYS)
- return Result::INVALID_STATE;
- else
- return Result::INVALID_ARGUMENTS;
+ return util::analyzeStatus(halStatus);
}
} // namespace implementation
index a4a820663ed546bdaccc53876bce293fe598e3b8..aaf899160cd34eed9168670477ad95b24599f1ef 100644 (file)
return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled);
}
+static const char* convertTtyModeFromHIDL(IPrimaryDevice::TtyMode mode) {
+ switch (mode) {
+ case IPrimaryDevice::TtyMode::OFF:
+ return AUDIO_PARAMETER_VALUE_TTY_OFF;
+ case IPrimaryDevice::TtyMode::VCO:
+ return AUDIO_PARAMETER_VALUE_TTY_VCO;
+ case IPrimaryDevice::TtyMode::HCO:
+ return AUDIO_PARAMETER_VALUE_TTY_HCO;
+ case IPrimaryDevice::TtyMode::FULL:
+ return AUDIO_PARAMETER_VALUE_TTY_FULL;
+ default:
+ return nullptr;
+ }
+}
+static IPrimaryDevice::TtyMode convertTtyModeToHIDL(const char* halMode) {
+ if (strcmp(halMode, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
+ return IPrimaryDevice::TtyMode::OFF;
+ else if (strcmp(halMode, AUDIO_PARAMETER_VALUE_TTY_VCO) == 0)
+ return IPrimaryDevice::TtyMode::VCO;
+ else if (strcmp(halMode, AUDIO_PARAMETER_VALUE_TTY_HCO) == 0)
+ return IPrimaryDevice::TtyMode::HCO;
+ else if (strcmp(halMode, AUDIO_PARAMETER_VALUE_TTY_FULL) == 0)
+ return IPrimaryDevice::TtyMode::FULL;
+ return IPrimaryDevice::TtyMode(-1);
+}
+
Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
- int halMode;
+ String8 halMode;
Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_TTY_MODE, &halMode);
- TtyMode mode = retval == Result::OK ? TtyMode(halMode) : TtyMode::OFF;
- _hidl_cb(retval, mode);
+ if (retval != Result::OK) {
+ _hidl_cb(retval, TtyMode::OFF);
+ return Void();
+ }
+ TtyMode mode = convertTtyModeToHIDL(halMode);
+ if (mode == TtyMode(-1)) {
+ ALOGE("HAL returned invalid TTY value: %s", halMode.c_str());
+ _hidl_cb(Result::INVALID_STATE, TtyMode::OFF);
+ return Void();
+ }
+ _hidl_cb(Result::OK, mode);
return Void();
}
Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
- return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE,
- static_cast<int>(mode));
+ const char* modeStr = convertTtyModeFromHIDL(mode);
+ if (modeStr == nullptr) {
+ ALOGW("Can not set an invalid TTY value: %d", mode);
+ return Result::INVALID_ARGUMENTS;
+ }
+ return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE, modeStr);
}
Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
index effdd285075d632ee2167dd995d7546fcdbbdd50..55ae6dbd014ceae26a743bbe02e0a9d76fa77df4 100644 (file)
#include "Conversions.h"
#include "EffectMap.h"
#include "Stream.h"
+#include "Util.h"
namespace android {
namespace hardware {
// static
Result Stream::analyzeStatus(const char* funcName, int status) {
- static const std::vector<int> empty;
- return analyzeStatus(funcName, status, empty);
+ return util::analyzeStatus("stream", funcName, status);
}
-template <typename T>
-inline bool element_in(T e, const std::vector<T>& v) {
- return std::find(v.begin(), v.end(), e) != v.end();
-}
// static
Result Stream::analyzeStatus(const char* funcName, int status,
const std::vector<int>& ignoreErrors) {
- if (status != 0 && (ignoreErrors.empty() || !element_in(-status, ignoreErrors))) {
- ALOGW("Error from HAL stream in function %s: %s", funcName, strerror(-status));
- }
- switch (status) {
- case 0: return Result::OK;
- case -EINVAL: return Result::INVALID_ARGUMENTS;
- case -ENODATA: return Result::INVALID_STATE;
- case -ENODEV: return Result::NOT_INITIALIZED;
- case -ENOSYS: return Result::NOT_SUPPORTED;
- default: return Result::INVALID_STATE;
- }
+ return util::analyzeStatus("stream", funcName, status, ignoreErrors);
}
char* Stream::halGetParameters(const char* keys) {
index 72eea5037bad13be7c71104688d8671a94b9778f..55019b8798df6fd1fbe0a2ffaf2c2145555587e7 100644 (file)
--- a/audio/2.0/default/Util.h
+++ b/audio/2.0/default/Util.h
#ifndef ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H
#define ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H
+#include <algorithm>
+#include <vector>
+
+#include <system/audio.h>
+
namespace android {
namespace hardware {
namespace audio {
return gain >= 0.0 && gain <= 1.0;
}
+namespace util {
+
+template <typename T>
+inline bool element_in(T e, const std::vector<T>& v) {
+ return std::find(v.begin(), v.end(), e) != v.end();
+}
+
+static inline Result analyzeStatus(status_t status) {
+ switch (status) {
+ case 0:
+ return Result::OK;
+ case -EINVAL:
+ return Result::INVALID_ARGUMENTS;
+ case -ENODATA:
+ return Result::INVALID_STATE;
+ case -ENODEV:
+ return Result::NOT_INITIALIZED;
+ case -ENOSYS:
+ return Result::NOT_SUPPORTED;
+ default:
+ return Result::INVALID_STATE;
+ }
+}
+
+static inline Result analyzeStatus(const char* className, const char* funcName, status_t status,
+ const std::vector<int>& ignoreErrors = {}) {
+ if (status != 0 && !element_in(-status, ignoreErrors)) {
+ ALOGW("Error from HAL %s in function %s: %s", className, funcName, strerror(-status));
+ }
+ return analyzeStatus(status);
+}
+
+} // namespace util
} // namespace implementation
} // namespace V2_0
} // namespace audio
index 8c3ec119d382a2f903b9b8aac48fbbedad8dc594..259c7c9e0536a9e1c56f2a3824c044b83d49208a 100644 (file)
uint32_t numAudioSources;
/** the hardware supports capture of audio source from audio HAL */
bool supportsCapture;
- vec<BandConfig> bands; /** band descriptors */
+ /** band descriptors */
+ vec<BandConfig> bands;
};
enum MetadataType : int32_t {
*/
uint32_t signalStrength;
- vec<MetaData> metadata; /** Metadata: PTY, song title etc. */
+ /** Metadata: PTY, song title etc. */
+ vec<MetaData> metadata;
};
index 23be7de2f92091400555acd92d107e500080fffc..cadf85b4c87c638b3c9dddbe3373f0c439c26011 100644 (file)
BUILD_FRAMEWORK_COMPATIBILITY_MATRIX := $(LOCAL_PATH)/compatibility_matrix.mk
-# Clear potential input variables to BUILD_FRAMEWORK_COMPATIBILITY_MATRIX
-LOCAL_ADD_VBMETA_VERSION :=
-LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
-LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE :=
-LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE :=
-LOCAL_ASSEMBLE_VINTF_FLAGS :=
-LOCAL_KERNEL_VERSIONS :=
-LOCAL_GEN_FILE_DEPENDENCIES :=
+my_kernel_config_data := kernel/configs
# Install all compatibility_matrix.*.xml to /system/etc/vintf
-
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
LOCAL_MODULE := framework_compatibility_matrix.legacy.xml
LOCAL_MODULE_STEM := compatibility_matrix.legacy.xml
LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
+LOCAL_KERNEL_CONFIG_DATA_PATHS := \
+ 3.18.0:$(my_kernel_config_data)/o/android-3.18 \
+ 4.4.0:$(my_kernel_config_data)/o/android-4.4 \
+ 4.9.0:$(my_kernel_config_data)/o/android-4.9 \
+
include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
LOCAL_MODULE := framework_compatibility_matrix.1.xml
LOCAL_MODULE_STEM := compatibility_matrix.1.xml
LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
+LOCAL_KERNEL_CONFIG_DATA_PATHS := \
+ 3.18.0:$(my_kernel_config_data)/o/android-3.18 \
+ 4.4.0:$(my_kernel_config_data)/o/android-4.4 \
+ 4.9.0:$(my_kernel_config_data)/o/android-4.9 \
+
include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
LOCAL_MODULE := framework_compatibility_matrix.2.xml
LOCAL_MODULE_STEM := compatibility_matrix.2.xml
LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
-include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
+LOCAL_KERNEL_CONFIG_DATA_PATHS := \
+ 3.18.0:$(my_kernel_config_data)/o-mr1/android-3.18 \
+ 4.4.0:$(my_kernel_config_data)/o-mr1/android-4.4 \
+ 4.9.0:$(my_kernel_config_data)/o-mr1/android-4.9 \
-# TODO(b/72409164): STOPSHIP: update kernel version requirements
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
LOCAL_MODULE := framework_compatibility_matrix.current.xml
LOCAL_MODULE_STEM := compatibility_matrix.current.xml
LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_KERNEL_VERSIONS := 4.4.0 4.9.0
+LOCAL_KERNEL_CONFIG_DATA_PATHS := \
+ 4.4.0:$(my_kernel_config_data)/android-4.4 \
+ 4.9.0:$(my_kernel_config_data)/android-4.9 \
+ 4.14.0:$(my_kernel_config_data)/android-4.14 \
+
include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
+my_kernel_config_data :=
+
# Framework Compatibility Matrix (common to all FCM versions)
include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
LOCAL_MODULE := framework_compatibility_matrix.device.xml
LOCAL_MODULE_STEM := compatibility_matrix.device.xml
# define LOCAL_MODULE_CLASS for local-generated-sources-dir.
PLATFORM_SEPOLICY_VERSION \
PLATFORM_SEPOLICY_COMPAT_VERSIONS
-LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE := PRODUCT_ENFORCE_VINTF_MANIFEST=true
-LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE := \
- "Error: DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX cannot contain required HALs."
-
include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-# Framework Compatibility Matrix
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := framework_compatibility_matrix.xml
-LOCAL_MODULE_STEM := compatibility_matrix.xml
-LOCAL_MODULE_PATH := $(TARGET_OUT)
-LOCAL_REQUIRED_MODULES := \
+my_system_matrix_deps := \
framework_compatibility_matrix.legacy.xml \
framework_compatibility_matrix.1.xml \
framework_compatibility_matrix.2.xml \
framework_compatibility_matrix.current.xml \
framework_compatibility_matrix.device.xml
+
+# Phony target that installs all framework compatibility matrix files
+include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.xml
+LOCAL_REQUIRED_MODULES := $(my_system_matrix_deps)
+include $(BUILD_PHONY_PACKAGE)
+
+# Final Framework Compatibility Matrix
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/clear_vars.mk
+LOCAL_MODULE := verified_assembled_system_matrix.xml
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)
+LOCAL_REQUIRED_MODULES := $(my_system_matrix_deps)
LOCAL_GENERATED_SOURCES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES))
ifdef BUILT_VENDOR_MANIFEST
LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(BUILT_VENDOR_MANIFEST)"
endif
-LOCAL_ASSEMBLE_VINTF_ENV_VARS := PRODUCT_ENFORCE_VINTF_MANIFEST
-
-# TODO(b/65028233): Enforce no "unused HALs" for devices that does not define
-# DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE as well
-ifeq (true,$(strip $(PRODUCT_ENFORCE_VINTF_MANIFEST)))
-ifdef DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE
-LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE := VINTF_ENFORCE_NO_UNUSED_HALS=true
-endif
-endif
-
include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
-BUILT_SYSTEM_COMPATIBILITY_MATRIX := $(LOCAL_BUILT_MODULE)
+BUILT_SYSTEM_MATRIX := $(LOCAL_BUILT_MODULE)
+my_system_matrix_deps :=
BUILD_FRAMEWORK_COMPATIBILITY_MATRIX :=
diff --git a/compatibility_matrices/clear_vars.mk b/compatibility_matrices/clear_vars.mk
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2017 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.
+#
+
+# Clear input variables to BUILD_FRAMEWORK_COMPATIBILITY_MATRIX
+LOCAL_ADD_VBMETA_VERSION :=
+LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
+LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE :=
+LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE :=
+LOCAL_ASSEMBLE_VINTF_FLAGS :=
+LOCAL_KERNEL_CONFIG_DATA_PATHS :=
+LOCAL_GEN_FILE_DEPENDENCIES :=
diff --git a/compatibility_matrices/compatibility_matrix.mk b/compatibility_matrices/compatibility_matrix.mk
index 6dc2b4fb69b3f73a6b373f9a1594b44212b794a9..1b6fd3b489fb2726f2690e3bde21622279e12753 100644 (file)
# limitations under the License.
#
-###########################################################
-## Remove minor revision from a kernel version. For example,
-## 3.18.0 becomes 3.18.
-## $(1): kernel version
-###########################################################
-define remove-minor-revision
-$(strip $(subst $(space),.,$(wordlist 1,2,$(subst .,$(space),$(strip $(1))))))
-endef
-
-# $(warning $(call remove-minor-revision,3.18.0))
-
##### Input Variables:
# LOCAL_MODULE: required. Module name for the build system.
# LOCAL_MODULE_CLASS: optional. Default is ETC.
# LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE: Add a list of environment variables that is local to
# assemble_vintf invocation. Format is "VINTF_ENFORCE_NO_UNUSED_HALS=true".
# LOCAL_ASSEMBLE_VINTF_FLAGS: Add additional command line arguments to assemble_vintf invocation.
-# LOCAL_KERNEL_VERSIONS: Parse kernel configurations and add to the output matrix
-# (corresponds to <kernel> tags.)
+# LOCAL_KERNEL_CONFIG_DATA_PATHS: Paths to search for kernel config requirements. Format for each is
+# <kernel version x.y.z>:<path that contains android-base*.cfg>.
# LOCAL_GEN_FILE_DEPENDENCIES: A list of additional dependencies for the generated file.
ifndef LOCAL_MODULE
$(GEN): PRIVATE_ENV_VARS += FRAMEWORK_VBMETA_VERSION
endif # LOCAL_ADD_VBMETA_VERSION
-ifneq (,$(strip $(LOCAL_KERNEL_VERSIONS)))
-$(GEN): PRIVATE_KERNEL_CONFIG_DATA := kernel/configs
-$(GEN): PRIVATE_KERNEL_VERSIONS := $(LOCAL_KERNEL_VERSIONS)
-$(GEN): $(foreach version,$(PRIVATE_KERNEL_VERSIONS),\
- $(wildcard $(PRIVATE_KERNEL_CONFIG_DATA)/android-$(call remove-minor-revision,$(version))/android-base*.cfg))
-$(GEN): PRIVATE_FLAGS += $(foreach version,$(PRIVATE_KERNEL_VERSIONS),\
- --kernel=$(version):$(call normalize-path-list,\
- $(wildcard $(PRIVATE_KERNEL_CONFIG_DATA)/android-$(call remove-minor-revision,$(version))/android-base*.cfg)))
+ifneq (,$(strip $(LOCAL_KERNEL_CONFIG_DATA_PATHS)))
+$(GEN): PRIVATE_KERNEL_CONFIG_DATA_PATHS := $(LOCAL_KERNEL_CONFIG_DATA_PATHS)
+$(GEN): $(foreach pair,$(PRIVATE_KERNEL_CONFIG_DATA_PATHS),\
+ $(wildcard $(call word-colon,2,$(pair))/android-base*.cfg))
+$(GEN): PRIVATE_FLAGS += $(foreach pair,$(PRIVATE_KERNEL_CONFIG_DATA_PATHS),\
+ --kernel=$(call word-colon,1,$(pair)):$(call normalize-path-list,\
+ $(wildcard $(call word-colon,2,$(pair))/android-base*.cfg)))
endif
my_matrix_src_files := \
LOCAL_SRC_FILES :=
LOCAL_GENERATED_SOURCES :=
-LOCAL_ADD_VBMETA_VERSION :=
-LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
-LOCAL_ASSEMBLE_VINTF_ENV_VARS_OVERRIDE :=
-LOCAL_ASSEMBLE_VINTF_ERROR_MESSAGE :=
-LOCAL_ASSEMBLE_VINTF_FLAGS :=
-LOCAL_KERNEL_VERSIONS :=
-LOCAL_GEN_FILE_DEPENDENCIES :=
+include $(LOCAL_PATH)/clear_vars.mk
my_matrix_src_files :=
include $(BUILD_PREBUILT)
-
-remove-minor-revision :=
index f7487d5864836f340dea8915e98490b9da5bc80b..19876076245f0c7e2a5125db6b13cbfb54e961c7 100644 (file)
LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
endif
-ifeq ($(TARGET_BOARD_PLATFORM),omap4)
- LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
-endif
-
-ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
- LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
-endif
-
ifeq ($(TARGET_USE_CONTEXT_PRIORITY),true)
LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
endif
diff --git a/configstore/README.md b/configstore/README.md
--- /dev/null
+++ b/configstore/README.md
@@ -0,0 +1 @@
+Configstore is specifically the configuration for surface flinger. Other configurations go in other packages.
index 93e52f1d4ed6b75786456888ddc8c6489a2944b1..0d626a50b21b25acd8b4e1140e99d4e5b93f9d0a 100644 (file)
vndk: {
enabled: true,
},
+ double_loadable: true,
defaults: ["hidl_defaults"],
srcs: [ "ConfigStoreUtils.cpp" ],
diff --git a/current.txt b/current.txt
index 990afcd6fa7b9f5e53bf2ba0affd77f9f5e4fe22..28f0f992b08174e16c87464243a40c170de521e7 100644 (file)
--- a/current.txt
+++ b/current.txt
@@ -238,10 +238,29 @@ a432d6d9200248dc2126827bcd6cdea31dd65eff39b939f64585d27d915a5857 android.hardwar
619600109232ed64b827c8a11beed8070b1827ae464547d7aa146cf0473b4bca android.hardware.cas.native@1.0::IDescrambler
0a159f81359cd4f71bbe00972ee8403ea79351fb7c0cd48be72ebb3e424dbaef android.hardware.radio@1.0::types
09342041e17c429fce0034b9096d17849122111436a5f0053e7e59500e1cb89c android.hardware.media.omx@1.0::IOmxStore
-246a56d37d57a47224562c9d077b4a2886ce6242b9311bd98a17325944c280d7 android.hardware.neuralnetworks@1.0::types
93eb3757ceaf21590fa4cd1d4a7dfe3b3794af5396100a6d25630879352abce9 android.hardware.neuralnetworks@1.0::IDevice
f66f9a38541bf92001d3adcce678cd7e3da2262124befb460b1c9aea9492813b android.hardware.neuralnetworks@1.0::IExecutionCallback
953607822954435874f4b81686440a604e2a88cdd2d9164c6293f3d5772510d7 android.hardware.neuralnetworks@1.0::IPreparedModel
73e03573494ba96f0e711ab7f1956c5b2d54c3da690cd7ecf4d6d0f287447730 android.hardware.neuralnetworks@1.0::IPreparedModelCallback
+246a56d37d57a47224562c9d077b4a2886ce6242b9311bd98a17325944c280d7 android.hardware.neuralnetworks@1.0::types
f4945e397b5dea41bb64518dfde59be71245d8a125fd1e0acffeb57ac7b08fed android.hardware.thermal@1.1::IThermal
c8bc853546dd55584611def2a9fa1d99f657e3366c976d2f60fe6b8aa6d2cb87 android.hardware.thermal@1.1::IThermalCallback
+
+# Future changes to HALs
+5804ca86611d72e5481f022b3a0c1b334217f2e4988dad25730c42af2d1f4d1c android.hardware.neuralnetworks@1.0::IDevice
+12e8dca4ab7d8aadd0ef8f1b438021938e2396139e85db2ed65783b08800aa52 android.hardware.neuralnetworks@1.0::IExecutionCallback
+18e6885e184fe48401c2c53f1d1b8bfb07240f40c81ae6b9d2e336fca6efdbb7 android.hardware.neuralnetworks@1.0::types
+
+# Documentation fixups for b/78135149
+9e7a0b650d0e461ece2cfec0e1072abf8676f592b41a7fb48f01e88fc3c8f780 android.hardware.broadcastradio@1.0::types
+190ea4898809de6cf379afe318f5fa9564686157b24d9a2d7f5698b0c977d8b2 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
+25892789b50eb673506b6c5a2cdab5d9aa428d41608aab10280cc898538b524a android.hardware.graphics.composer@2.1::IComposerClient
+e205dd30f5ff99445b706a901de8ebc46c379e9d7c1921d6a327ed2082cfa83d android.hardware.graphics.composer@2.1::types
+a46251718abfada458dc64c41ce94915757bf6c87cfa2d9e99cfb01fa8e32331 android.hardware.graphics.mapper@2.0::IMapper
+bd33ac23c57b4a07632691d2191bc2c93930f57e62f4ccf459748fdaa5c0f480 android.hardware.graphics.mapper@2.0::types
+ad8a28ca3a5549fb9bc24cf5f80ac8f660cc27be885210d76266780aa52ddb8d android.hardware.keymaster@3.0::types
+f96cbc59dfe16c8d0c2a7e06db24d8738a6328b6e90f7b8e1640ea2b4600debd android.hardware.radio@1.1::ISap
+2d86929794795e5c70f4fdb5073485fd05835c9c6f496116687c3d9f32e6df3e android.hardware.radio@1.2::ISap
+905a4af79c8329b39d8b11b08f015137216bb078b427b6986f32884a04bc1bec android.hardware.tv.cec@1.0::types
+aebcd9ff2da05c9d4c439916f40dfd219ba7629919007cb981ebf150064b4f82 android.hardware.usb@1.1::IUsb
+e29fb1941b40a990676f8e9c676a38761defd890b81a9c034608eb7ba6496023 android.hardware.wifi@1.0::IWifiP2pIface
index 818a53127cfb7580035bee409fc4d5fd7d1cff63..88623afd7ff2626725d50b48cee3666bf90046d1 100644 (file)
#include "DumpstateDevice.h"
+#include <hidl/HidlBinderSupport.h>
#include <log/log.h>
#include "DumpstateUtil.h"
// this interface - since HIDL_FETCH_IDumpstateDevice() is not defined, this function will never
// be called by dumpstate.
+ // Exit when dump is completed since this is a lazy HAL.
+ addPostCommandTask([]() {
+ exit(0);
+ });
+
if (handle == nullptr || handle->numFds < 1) {
ALOGE("no FDs\n");
return Void();
diff --git a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
index 0f27248512e4f22534c2c01a84fb23ffe0ae2d75..dfbfb33553c11d67e69b67b474530c81a6f9f1f6 100644 (file)
class hal
user system
group system
+ interface android.hardware.dumpstate@1.0::IDumpstateDevice default
+ oneshot
+ disabled
diff --git a/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
index 87bb814ab5e6f4737e454890150cf6924d12f489..c59a16ccbd1c59937675b2a8a82eaec2c8a2aa31 100644 (file)
*/
disconnect(
int32_t api,
- DisconnectMode mode /** = DisconnectMode::API */
+ DisconnectMode mode /* = DisconnectMode::API */
) generates (
Status status
);
index f2ff932f183d95f8272f6cd44fda13f695a01a31..5ad46f01134a314fea5c2915f7639d0af6ec8774 100644 (file)
SET_LAYER_Z_ORDER = 0x40a << OPCODE_SHIFT,
SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT = 0x40b << OPCODE_SHIFT,
- /** 0x800 - 0xfff are reserved for vendor extensions */
- /** 0x1000 - 0xffff are reserved */
+ /* 0x800 - 0xfff are reserved for vendor extensions */
+ /* 0x1000 - 0xffff are reserved */
};
};
index 9f0dd8bc4f6801e96860fcc48f67a06982194c91..eb0a73bb6aadf3a3a88c56c2cf6d568bbada770d 100644 (file)
/** Return codes from all functions. */
enum Error : int32_t {
- NONE = 0, /** no error */
- BAD_CONFIG = 1, /** invalid Config */
- BAD_DISPLAY = 2, /** invalid Display */
- BAD_LAYER = 3, /** invalid Layer */
- BAD_PARAMETER = 4, /** invalid width, height, etc. */
- /** 5 is reserved */
- NO_RESOURCES = 6, /** temporary failure due to resource contention */
- NOT_VALIDATED = 7, /** validateDisplay has not been called */
- UNSUPPORTED = 8, /** permanent failure */
+ NONE = 0, /* no error */
+ BAD_CONFIG = 1, /* invalid Config */
+ BAD_DISPLAY = 2, /* invalid Display */
+ BAD_LAYER = 3, /* invalid Layer */
+ BAD_PARAMETER = 4, /* invalid width, height, etc. */
+ /* 5 is reserved */
+ NO_RESOURCES = 6, /* temporary failure due to resource contention */
+ NOT_VALIDATED = 7, /* validateDisplay has not been called */
+ UNSUPPORTED = 8, /* permanent failure */
};
typedef uint32_t Config;
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2010 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_shared {
+ name: "libhwc2on1adapter",
+ vendor: true,
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-user-defined-warnings",
+ ],
+ cppflags: [
+ "-Weverything",
+ "-Wunused",
+ "-Wunreachable-code",
+
+ // The static constructors and destructors in this library have not been noted to
+ // introduce significant overheads
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+
+ // We only care about compiling as C++14
+ "-Wno-c++98-compat-pedantic",
+
+ // android/sensors.h uses nested anonymous unions and anonymous structs
+ "-Wno-nested-anon-types",
+ "-Wno-gnu-anonymous-struct",
+
+ // Don't warn about struct padding
+ "-Wno-padded",
+
+ // hwcomposer2.h features switch covering all cases.
+ "-Wno-covered-switch-default",
+
+ // hwcomposer.h features zero size array.
+ "-Wno-zero-length-array",
+
+ // Disabling warning specific to hwc2on1adapter code
+ "-Wno-double-promotion",
+ "-Wno-sign-conversion",
+ "-Wno-switch-enum",
+ "-Wno-float-equal",
+ "-Wno-shorten-64-to-32",
+ "-Wno-sign-compare",
+ "-Wno-missing-prototypes",
+ ],
+
+ srcs: [
+ "HWC2On1Adapter.cpp",
+ "MiniFence.cpp",
+ ],
+
+ shared_libs: [
+ "libutils",
+ "libcutils",
+ "liblog",
+ "libhardware",
+ ],
+
+ export_include_dirs: ["include"],
+
+ export_shared_lib_headers: ["libutils"],
+}
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk b/graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2017 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so)
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
--- /dev/null
@@ -0,0 +1,2636 @@
+/*
+ * Copyright 2015 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 "hwc2on1adapter/HWC2On1Adapter.h"
+
+//#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "HWC2On1Adapter"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+
+#include <inttypes.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <sstream>
+
+#include <hardware/hwcomposer.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
+{
+ auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+ return (version >> 16) & 0xF;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function)
+{
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+using namespace HWC2;
+
+static constexpr Attribute ColorMode = static_cast<Attribute>(6);
+
+namespace android {
+
+class HWC2On1Adapter::Callbacks : public hwc_procs_t {
+ public:
+ explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
+ invalidate = &invalidateHook;
+ vsync = &vsyncHook;
+ hotplug = &hotplugHook;
+ }
+
+ static void invalidateHook(const hwc_procs_t* procs) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Invalidate();
+ }
+
+ static void vsyncHook(const hwc_procs_t* procs, int display,
+ int64_t timestamp) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Vsync(display, timestamp);
+ }
+
+ static void hotplugHook(const hwc_procs_t* procs, int display,
+ int connected) {
+ auto callbacks = static_cast<const Callbacks*>(procs);
+ callbacks->mAdapter.hwc1Hotplug(display, connected);
+ }
+
+ private:
+ HWC2On1Adapter& mAdapter;
+};
+
+static int closeHook(hw_device_t* /*device*/)
+{
+ // Do nothing, since the real work is done in the class destructor, but we
+ // need to provide a valid function pointer for hwc2_close to call
+ return 0;
+}
+
+HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device)
+ : mDumpString(),
+ mHwc1Device(hwc1Device),
+ mHwc1MinorVersion(getMinorVersion(hwc1Device)),
+ mHwc1SupportsVirtualDisplays(false),
+ mHwc1SupportsBackgroundColor(false),
+ mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
+ mCapabilities(),
+ mLayers(),
+ mHwc1VirtualDisplay(),
+ mStateMutex(),
+ mCallbacks(),
+ mHasPendingInvalidate(false),
+ mPendingVsyncs(),
+ mPendingHotplugs(),
+ mDisplays(),
+ mHwc1DisplayMap()
+{
+ common.close = closeHook;
+ getCapabilities = getCapabilitiesHook;
+ getFunction = getFunctionHook;
+ populateCapabilities();
+ populatePrimary();
+ mHwc1Device->registerProcs(mHwc1Device,
+ static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
+}
+
+HWC2On1Adapter::~HWC2On1Adapter() {
+ hwc_close_1(mHwc1Device);
+}
+
+void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount,
+ int32_t* outCapabilities) {
+ if (outCapabilities == nullptr) {
+ *outCount = mCapabilities.size();
+ return;
+ }
+
+ auto capabilityIter = mCapabilities.cbegin();
+ for (size_t written = 0; written < *outCount; ++written) {
+ if (capabilityIter == mCapabilities.cend()) {
+ return;
+ }
+ outCapabilities[written] = static_cast<int32_t>(*capabilityIter);
+ ++capabilityIter;
+ }
+}
+
+hwc2_function_pointer_t HWC2On1Adapter::doGetFunction(
+ FunctionDescriptor descriptor) {
+ switch (descriptor) {
+ // Device functions
+ case FunctionDescriptor::CreateVirtualDisplay:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+ createVirtualDisplayHook);
+ case FunctionDescriptor::DestroyVirtualDisplay:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+ destroyVirtualDisplayHook);
+ case FunctionDescriptor::Dump:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case FunctionDescriptor::GetMaxVirtualDisplayCount:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+ getMaxVirtualDisplayCountHook);
+ case FunctionDescriptor::RegisterCallback:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // Display functions
+ case FunctionDescriptor::AcceptDisplayChanges:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+ displayHook<decltype(&Display::acceptChanges),
+ &Display::acceptChanges>);
+ case FunctionDescriptor::CreateLayer:
+ return asFP<HWC2_PFN_CREATE_LAYER>(
+ displayHook<decltype(&Display::createLayer),
+ &Display::createLayer, hwc2_layer_t*>);
+ case FunctionDescriptor::DestroyLayer:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(
+ displayHook<decltype(&Display::destroyLayer),
+ &Display::destroyLayer, hwc2_layer_t>);
+ case FunctionDescriptor::GetActiveConfig:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::getActiveConfig),
+ &Display::getActiveConfig, hwc2_config_t*>);
+ case FunctionDescriptor::GetChangedCompositionTypes:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+ displayHook<decltype(&Display::getChangedCompositionTypes),
+ &Display::getChangedCompositionTypes, uint32_t*,
+ hwc2_layer_t*, int32_t*>);
+ case FunctionDescriptor::GetColorModes:
+ return asFP<HWC2_PFN_GET_COLOR_MODES>(
+ displayHook<decltype(&Display::getColorModes),
+ &Display::getColorModes, uint32_t*, int32_t*>);
+ case FunctionDescriptor::GetDisplayAttribute:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+ getDisplayAttributeHook);
+ case FunctionDescriptor::GetDisplayConfigs:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+ displayHook<decltype(&Display::getConfigs),
+ &Display::getConfigs, uint32_t*, hwc2_config_t*>);
+ case FunctionDescriptor::GetDisplayName:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
+ displayHook<decltype(&Display::getName),
+ &Display::getName, uint32_t*, char*>);
+ case FunctionDescriptor::GetDisplayRequests:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+ displayHook<decltype(&Display::getRequests),
+ &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::GetDisplayType:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
+ displayHook<decltype(&Display::getType),
+ &Display::getType, int32_t*>);
+ case FunctionDescriptor::GetDozeSupport:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
+ displayHook<decltype(&Display::getDozeSupport),
+ &Display::getDozeSupport, int32_t*>);
+ case FunctionDescriptor::GetHdrCapabilities:
+ return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
+ displayHook<decltype(&Display::getHdrCapabilities),
+ &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
+ float*, float*>);
+ case FunctionDescriptor::GetReleaseFences:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
+ displayHook<decltype(&Display::getReleaseFences),
+ &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::PresentDisplay:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(
+ displayHook<decltype(&Display::present),
+ &Display::present, int32_t*>);
+ case FunctionDescriptor::SetActiveConfig:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::setActiveConfig),
+ &Display::setActiveConfig, hwc2_config_t>);
+ case FunctionDescriptor::SetClientTarget:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
+ displayHook<decltype(&Display::setClientTarget),
+ &Display::setClientTarget, buffer_handle_t, int32_t,
+ int32_t, hwc_region_t>);
+ case FunctionDescriptor::SetColorMode:
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
+ case FunctionDescriptor::SetColorTransform:
+ return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
+ case FunctionDescriptor::SetOutputBuffer:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
+ displayHook<decltype(&Display::setOutputBuffer),
+ &Display::setOutputBuffer, buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetPowerMode:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+ case FunctionDescriptor::SetVsyncEnabled:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+ case FunctionDescriptor::ValidateDisplay:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
+ displayHook<decltype(&Display::validate),
+ &Display::validate, uint32_t*, uint32_t*>);
+ case FunctionDescriptor::GetClientTargetSupport:
+ return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+ displayHook<decltype(&Display::getClientTargetSupport),
+ &Display::getClientTargetSupport, uint32_t, uint32_t,
+ int32_t, int32_t>);
+
+ // Layer functions
+ case FunctionDescriptor::SetCursorPosition:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
+ layerHook<decltype(&Layer::setCursorPosition),
+ &Layer::setCursorPosition, int32_t, int32_t>);
+ case FunctionDescriptor::SetLayerBuffer:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
+ layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
+ buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetLayerSurfaceDamage:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+ layerHook<decltype(&Layer::setSurfaceDamage),
+ &Layer::setSurfaceDamage, hwc_region_t>);
+
+ // Layer state functions
+ case FunctionDescriptor::SetLayerBlendMode:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+ setLayerBlendModeHook);
+ case FunctionDescriptor::SetLayerColor:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(
+ layerHook<decltype(&Layer::setColor), &Layer::setColor,
+ hwc_color_t>);
+ case FunctionDescriptor::SetLayerCompositionType:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+ setLayerCompositionTypeHook);
+ case FunctionDescriptor::SetLayerDataspace:
+ return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerDataspaceHook);
+ case FunctionDescriptor::SetLayerDisplayFrame:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+ layerHook<decltype(&Layer::setDisplayFrame),
+ &Layer::setDisplayFrame, hwc_rect_t>);
+ case FunctionDescriptor::SetLayerPlaneAlpha:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+ layerHook<decltype(&Layer::setPlaneAlpha),
+ &Layer::setPlaneAlpha, float>);
+ case FunctionDescriptor::SetLayerSidebandStream:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+ layerHook<decltype(&Layer::setSidebandStream),
+ &Layer::setSidebandStream, const native_handle_t*>);
+ case FunctionDescriptor::SetLayerSourceCrop:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+ layerHook<decltype(&Layer::setSourceCrop),
+ &Layer::setSourceCrop, hwc_frect_t>);
+ case FunctionDescriptor::SetLayerTransform:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerTransformHook);
+ case FunctionDescriptor::SetLayerVisibleRegion:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+ layerHook<decltype(&Layer::setVisibleRegion),
+ &Layer::setVisibleRegion, hwc_region_t>);
+ case FunctionDescriptor::SetLayerZOrder:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerZOrderHook);
+
+ default:
+ ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
+ static_cast<int32_t>(descriptor),
+ to_string(descriptor).c_str());
+ return nullptr;
+ }
+}
+
+// Device functions
+
+Error HWC2On1Adapter::createVirtualDisplay(uint32_t width,
+ uint32_t height, hwc2_display_t* outDisplay) {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ if (mHwc1VirtualDisplay) {
+ // We have already allocated our only HWC1 virtual display
+ ALOGE("createVirtualDisplay: HWC1 virtual display already allocated");
+ return Error::NoResources;
+ }
+
+ mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
+ HWC2::DisplayType::Virtual);
+ mHwc1VirtualDisplay->populateConfigs(width, height);
+ const auto displayId = mHwc1VirtualDisplay->getId();
+ mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId;
+ mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL);
+ mDisplays.emplace(displayId, mHwc1VirtualDisplay);
+ *outDisplay = displayId;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId) {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
+ return Error::BadDisplay;
+ }
+
+ mHwc1VirtualDisplay.reset();
+ mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL);
+ mDisplays.erase(displayId);
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer) {
+ if (outBuffer != nullptr) {
+ auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
+ *outSize = static_cast<uint32_t>(copiedBytes);
+ return;
+ }
+
+ std::stringstream output;
+
+ output << "-- HWC2On1Adapter --\n";
+
+ output << "Adapting to a HWC 1." << static_cast<int>(mHwc1MinorVersion) <<
+ " device\n";
+
+ // Attempt to acquire the lock for 1 second, but proceed without the lock
+ // after that, so we can still get some information if we're deadlocked
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex,
+ std::defer_lock);
+ lock.try_lock_for(1s);
+
+ if (mCapabilities.empty()) {
+ output << "Capabilities: None\n";
+ } else {
+ output << "Capabilities:\n";
+ for (auto capability : mCapabilities) {
+ output << " " << to_string(capability) << '\n';
+ }
+ }
+
+ output << "Displays:\n";
+ for (const auto& element : mDisplays) {
+ const auto& display = element.second;
+ output << display->dump();
+ }
+ output << '\n';
+
+ // Release the lock before calling into HWC1, and since we no longer require
+ // mutual exclusion to access mCapabilities or mDisplays
+ lock.unlock();
+
+ if (mHwc1Device->dump) {
+ output << "HWC1 dump:\n";
+ std::vector<char> hwc1Dump(4096);
+ // Call with size - 1 to preserve a null character at the end
+ mHwc1Device->dump(mHwc1Device, hwc1Dump.data(),
+ static_cast<int>(hwc1Dump.size() - 1));
+ output << hwc1Dump.data();
+ }
+
+ mDumpString = output.str();
+ *outSize = static_cast<uint32_t>(mDumpString.size());
+}
+
+uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount() {
+ return mHwc1SupportsVirtualDisplays ? 1 : 0;
+}
+
+static bool isValid(Callback descriptor) {
+ switch (descriptor) {
+ case Callback::Hotplug: // Fall-through
+ case Callback::Refresh: // Fall-through
+ case Callback::Vsync: return true;
+ default: return false;
+ }
+}
+
+Error HWC2On1Adapter::registerCallback(Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+ if (!isValid(descriptor)) {
+ return Error::BadParameter;
+ }
+
+ ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
+ callbackData, pointer);
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ if (pointer != nullptr) {
+ mCallbacks[descriptor] = {callbackData, pointer};
+ } else {
+ ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
+ mCallbacks.erase(descriptor);
+ return Error::None;
+ }
+
+ bool hasPendingInvalidate = false;
+ std::vector<hwc2_display_t> displayIds;
+ std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
+ std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
+
+ if (descriptor == Callback::Refresh) {
+ hasPendingInvalidate = mHasPendingInvalidate;
+ if (hasPendingInvalidate) {
+ for (auto& displayPair : mDisplays) {
+ displayIds.emplace_back(displayPair.first);
+ }
+ }
+ mHasPendingInvalidate = false;
+ } else if (descriptor == Callback::Vsync) {
+ for (auto pending : mPendingVsyncs) {
+ auto hwc1DisplayId = pending.first;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
+ hwc1DisplayId);
+ continue;
+ }
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+ auto timestamp = pending.second;
+ pendingVsyncs.emplace_back(displayId, timestamp);
+ }
+ mPendingVsyncs.clear();
+ } else if (descriptor == Callback::Hotplug) {
+ // Hotplug the primary display
+ pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
+ static_cast<int32_t>(Connection::Connected));
+
+ for (auto pending : mPendingHotplugs) {
+ auto hwc1DisplayId = pending.first;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
+ hwc1DisplayId);
+ continue;
+ }
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+ auto connected = pending.second;
+ pendingHotplugs.emplace_back(displayId, connected);
+ }
+ }
+
+ // Call pending callbacks without the state lock held
+ lock.unlock();
+
+ if (hasPendingInvalidate) {
+ auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
+ for (auto displayId : displayIds) {
+ refresh(callbackData, displayId);
+ }
+ }
+ if (!pendingVsyncs.empty()) {
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
+ for (auto& pendingVsync : pendingVsyncs) {
+ vsync(callbackData, pendingVsync.first, pendingVsync.second);
+ }
+ }
+ if (!pendingHotplugs.empty()) {
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
+ for (auto& pendingHotplug : pendingHotplugs) {
+ hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
+ }
+ }
+ return Error::None;
+}
+
+// Display functions
+
+std::atomic<hwc2_display_t> HWC2On1Adapter::Display::sNextId(1);
+
+HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type)
+ : mId(sNextId++),
+ mDevice(device),
+ mStateMutex(),
+ mHwc1RequestedContents(nullptr),
+ mRetireFence(),
+ mChanges(),
+ mHwc1Id(-1),
+ mConfigs(),
+ mActiveConfig(nullptr),
+ mActiveColorMode(static_cast<android_color_mode_t>(-1)),
+ mName(),
+ mType(type),
+ mPowerMode(PowerMode::Off),
+ mVsyncEnabled(Vsync::Invalid),
+ mClientTarget(),
+ mOutputBuffer(),
+ mHasColorTransform(false),
+ mLayers(),
+ mHwc1LayerMap(),
+ mNumAvailableRects(0),
+ mNextAvailableRect(nullptr),
+ mGeometryChanged(false)
+ {}
+
+Error HWC2On1Adapter::Display::acceptChanges() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId);
+ return Error::NotValidated;
+ }
+
+ ALOGV("[%" PRIu64 "] acceptChanges", mId);
+
+ for (auto& change : mChanges->getTypeChanges()) {
+ auto layerId = change.first;
+ auto type = change.second;
+ if (mDevice.mLayers.count(layerId) == 0) {
+ // This should never happen but somehow does.
+ ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+ layerId);
+ continue;
+ }
+ auto layer = mDevice.mLayers[layerId];
+ layer->setCompositionType(type);
+ }
+
+ mChanges->clearTypeChanges();
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
+ mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
+ *outLayerId = layer->getId();
+ ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
+ markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer",
+ mId, layerId);
+ return Error::BadLayer;
+ }
+ const auto layer = mapLayer->second;
+ mDevice.mLayers.erase(mapLayer);
+ const auto zRange = mLayers.equal_range(layer);
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ current = mLayers.erase(current);
+ break;
+ }
+ }
+ ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
+ markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mActiveConfig) {
+ ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId,
+ to_string(Error::BadConfig).c_str());
+ return Error::BadConfig;
+ }
+ auto configId = mActiveConfig->getId();
+ ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId);
+ *outConfig = configId;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId,
+ Attribute attribute, int32_t* outValue) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId,
+ configId);
+ return Error::BadConfig;
+ }
+ *outValue = mConfigs[configId]->getAttribute(attribute);
+ ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId,
+ to_string(attribute).c_str(), *outValue);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getChangedCompositionTypes(
+ uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated",
+ mId);
+ return Error::NotValidated;
+ }
+
+ if ((outLayers == nullptr) || (outTypes == nullptr)) {
+ *outNumElements = mChanges->getTypeChanges().size();
+ return Error::None;
+ }
+
+ uint32_t numWritten = 0;
+ for (const auto& element : mChanges->getTypeChanges()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ auto layerId = element.first;
+ auto intType = static_cast<int32_t>(element.second);
+ ALOGV("Adding %" PRIu64 " %s", layerId,
+ to_string(element.second).c_str());
+ outLayers[numWritten] = layerId;
+ outTypes[numWritten] = intType;
+ ++numWritten;
+ }
+ *outNumElements = numWritten;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getColorModes(uint32_t* outNumModes,
+ int32_t* outModes) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outModes) {
+ *outNumModes = mColorModes.size();
+ return Error::None;
+ }
+ uint32_t numModes = std::min(*outNumModes,
+ static_cast<uint32_t>(mColorModes.size()));
+ std::copy_n(mColorModes.cbegin(), numModes, outModes);
+ *outNumModes = numModes;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigs) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outConfigs) {
+ *outNumConfigs = mConfigs.size();
+ return Error::None;
+ }
+ uint32_t numWritten = 0;
+ for (const auto& config : mConfigs) {
+ if (numWritten == *outNumConfigs) {
+ break;
+ }
+ outConfigs[numWritten] = config->getId();
+ ++numWritten;
+ }
+ *outNumConfigs = numWritten;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
+ *outSupport = 0;
+ } else {
+ *outSupport = 1;
+ }
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
+ int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
+ *outNumTypes = 0;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!outName) {
+ *outSize = mName.size();
+ return Error::None;
+ }
+ auto numCopied = mName.copy(outName, *outSize);
+ *outSize = numCopied;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outFences) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ uint32_t numWritten = 0;
+ bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr);
+ for (const auto& layer : mLayers) {
+ if (outputsNonNull && (numWritten == *outNumElements)) {
+ break;
+ }
+
+ auto releaseFence = layer->getReleaseFence();
+ if (releaseFence != MiniFence::NO_FENCE) {
+ if (outputsNonNull) {
+ outLayers[numWritten] = layer->getId();
+ outFences[numWritten] = releaseFence->dup();
+ }
+ ++numWritten;
+ }
+ }
+ *outNumElements = numWritten;
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ return Error::NotValidated;
+ }
+
+ if (outLayers == nullptr || outLayerRequests == nullptr) {
+ *outNumElements = mChanges->getNumLayerRequests();
+ return Error::None;
+ }
+
+ // Display requests (HWC2::DisplayRequest) are not supported by hwc1:
+ // A hwc1 has always zero requests for the client.
+ *outDisplayRequests = 0;
+
+ uint32_t numWritten = 0;
+ for (const auto& request : mChanges->getLayerRequests()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ outLayers[numWritten] = request.first;
+ outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
+ ++numWritten;
+ }
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getType(int32_t* outType) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ *outType = static_cast<int32_t>(mType);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::present(int32_t* outRetireFence) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (mChanges) {
+ Error error = mDevice.setAllDisplays();
+ if (error != Error::None) {
+ ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId,
+ to_string(error).c_str());
+ return error;
+ }
+ }
+
+ *outRetireFence = mRetireFence.get()->dup();
+ ALOGV("[%" PRIu64 "] present returning retire fence %d", mId,
+ *outRetireFence);
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ auto config = getConfig(configId);
+ if (!config) {
+ return Error::BadConfig;
+ }
+ if (config == mActiveConfig) {
+ return Error::None;
+ }
+
+ if (mDevice.mHwc1MinorVersion >= 4) {
+ uint32_t hwc1Id = 0;
+ auto error = config->getHwc1IdForColorMode(mActiveColorMode, &hwc1Id);
+ if (error != Error::None) {
+ return error;
+ }
+
+ int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+ mHwc1Id, static_cast<int>(hwc1Id));
+ if (intError != 0) {
+ ALOGE("setActiveConfig: Failed to set active config on HWC1 (%d)",
+ intError);
+ return Error::BadConfig;
+ }
+ mActiveConfig = config;
+ }
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
+ mClientTarget.setBuffer(target);
+ mClientTarget.setFence(acquireFence);
+ // dataspace and damage can't be used by HWC1, so ignore them
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode) {
+ std::unique_lock<std::recursive_mutex> lock (mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode);
+
+ if (mode == mActiveColorMode) {
+ return Error::None;
+ }
+ if (mColorModes.count(mode) == 0) {
+ ALOGE("[%" PRIu64 "] Mode %d not found in mColorModes", mId, mode);
+ return Error::Unsupported;
+ }
+
+ uint32_t hwc1Config = 0;
+ auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
+ if (error != Error::None) {
+ return error;
+ }
+
+ ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
+ int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
+ mHwc1Id, hwc1Config);
+ if (intError != 0) {
+ ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
+ return Error::Unsupported;
+ }
+
+ mActiveColorMode = mode;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("%" PRIu64 "] setColorTransform(%d)", mId,
+ static_cast<int32_t>(hint));
+ mHasColorTransform = (hint != HAL_COLOR_TRANSFORM_IDENTITY);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer,
+ int32_t releaseFence) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
+ mOutputBuffer.setBuffer(buffer);
+ mOutputBuffer.setFence(releaseFence);
+ return Error::None;
+}
+
+static bool isValid(PowerMode mode) {
+ switch (mode) {
+ case PowerMode::Off: // Fall-through
+ case PowerMode::DozeSuspend: // Fall-through
+ case PowerMode::Doze: // Fall-through
+ case PowerMode::On: return true;
+ }
+}
+
+static int getHwc1PowerMode(PowerMode mode) {
+ switch (mode) {
+ case PowerMode::Off: return HWC_POWER_MODE_OFF;
+ case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
+ case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
+ case PowerMode::On: return HWC_POWER_MODE_NORMAL;
+ }
+}
+
+Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode) {
+ if (!isValid(mode)) {
+ return Error::BadParameter;
+ }
+ if (mode == mPowerMode) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ int error = 0;
+ if (mDevice.mHwc1MinorVersion < 4) {
+ error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id,
+ mode == PowerMode::Off);
+ } else {
+ error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device,
+ mHwc1Id, getHwc1PowerMode(mode));
+ }
+ ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)",
+ error);
+
+ ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str());
+ mPowerMode = mode;
+ return Error::None;
+}
+
+static bool isValid(Vsync enable) {
+ switch (enable) {
+ case Vsync::Enable: // Fall-through
+ case Vsync::Disable: return true;
+ case Vsync::Invalid: return false;
+ }
+}
+
+Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable) {
+ if (!isValid(enable)) {
+ return Error::BadParameter;
+ }
+ if (enable == mVsyncEnabled) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device,
+ mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable);
+ ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)",
+ error);
+
+ mVsyncEnabled = enable;
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ if (!mDevice.prepareAllDisplays()) {
+ return Error::BadDisplay;
+ }
+ } else {
+ ALOGE("Validate was called more than once!");
+ }
+
+ *outNumTypes = mChanges->getNumTypes();
+ *outNumRequests = mChanges->getNumLayerRequests();
+ ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes,
+ *outNumRequests);
+ for (auto request : mChanges->getTypeChanges()) {
+ ALOGV("Layer %" PRIu64 " --> %s", request.first,
+ to_string(request.second).c_str());
+ }
+ return *outNumTypes > 0 ? Error::HasChanges : Error::None;
+}
+
+Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId);
+ return Error::BadLayer;
+ }
+
+ const auto layer = mapLayer->second;
+ const auto zRange = mLayers.equal_range(layer);
+ bool layerOnDisplay = false;
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ if ((*current)->getZ() == z) {
+ // Don't change anything if the Z hasn't changed
+ return Error::None;
+ }
+ current = mLayers.erase(current);
+ layerOnDisplay = true;
+ break;
+ }
+ }
+
+ if (!layerOnDisplay) {
+ ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display",
+ mId);
+ return Error::BadLayer;
+ }
+
+ layer->setZ(z);
+ mLayers.emplace(std::move(layer));
+ markGeometryChanged();
+
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Display::getClientTargetSupport(uint32_t width, uint32_t height,
+ int32_t format, int32_t dataspace){
+ if (mActiveConfig == nullptr) {
+ return Error::Unsupported;
+ }
+
+ if (width == mActiveConfig->getAttribute(Attribute::Width) &&
+ height == mActiveConfig->getAttribute(Attribute::Height) &&
+ format == HAL_PIXEL_FORMAT_RGBA_8888 &&
+ dataspace == HAL_DATASPACE_UNKNOWN) {
+ return Error::None;
+ }
+
+ return Error::Unsupported;
+}
+
+static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_COLOR_TRANSFORM,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static constexpr uint32_t ATTRIBUTES_WITHOUT_COLOR[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+static constexpr size_t NUM_ATTRIBUTES_WITH_COLOR =
+ sizeof(ATTRIBUTES_WITH_COLOR) / sizeof(uint32_t);
+static_assert(sizeof(ATTRIBUTES_WITH_COLOR) > sizeof(ATTRIBUTES_WITHOUT_COLOR),
+ "Attribute tables have unexpected sizes");
+
+static constexpr uint32_t ATTRIBUTE_MAP_WITH_COLOR[] = {
+ 6, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+ 0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+ 1, // HWC_DISPLAY_WIDTH = 2,
+ 2, // HWC_DISPLAY_HEIGHT = 3,
+ 3, // HWC_DISPLAY_DPI_X = 4,
+ 4, // HWC_DISPLAY_DPI_Y = 5,
+ 5, // HWC_DISPLAY_COLOR_TRANSFORM = 6,
+};
+
+static constexpr uint32_t ATTRIBUTE_MAP_WITHOUT_COLOR[] = {
+ 5, // HWC_DISPLAY_NO_ATTRIBUTE = 0
+ 0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
+ 1, // HWC_DISPLAY_WIDTH = 2,
+ 2, // HWC_DISPLAY_HEIGHT = 3,
+ 3, // HWC_DISPLAY_DPI_X = 4,
+ 4, // HWC_DISPLAY_DPI_Y = 5,
+};
+
+template <uint32_t attribute>
+static constexpr bool attributesMatch()
+{
+ bool match = (attribute ==
+ ATTRIBUTES_WITH_COLOR[ATTRIBUTE_MAP_WITH_COLOR[attribute]]);
+ if (attribute == HWC_DISPLAY_COLOR_TRANSFORM) {
+ return match;
+ }
+
+ return match && (attribute ==
+ ATTRIBUTES_WITHOUT_COLOR[ATTRIBUTE_MAP_WITHOUT_COLOR[attribute]]);
+}
+static_assert(attributesMatch<HWC_DISPLAY_VSYNC_PERIOD>(),
+ "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_WIDTH>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_HEIGHT>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_X>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_DPI_Y>(), "Tables out of sync");
+static_assert(attributesMatch<HWC_DISPLAY_COLOR_TRANSFORM>(),
+ "Tables out of sync");
+
+void HWC2On1Adapter::Display::populateConfigs() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ ALOGV("[%" PRIu64 "] populateConfigs", mId);
+
+ if (mHwc1Id == -1) {
+ ALOGE("populateConfigs: HWC1 ID not set");
+ return;
+ }
+
+ const size_t MAX_NUM_CONFIGS = 128;
+ uint32_t configs[MAX_NUM_CONFIGS] = {};
+ size_t numConfigs = MAX_NUM_CONFIGS;
+ mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id,
+ configs, &numConfigs);
+
+ for (size_t c = 0; c < numConfigs; ++c) {
+ uint32_t hwc1ConfigId = configs[c];
+ auto newConfig = std::make_shared<Config>(*this);
+
+ int32_t values[NUM_ATTRIBUTES_WITH_COLOR] = {};
+ bool hasColor = true;
+ auto result = mDevice.mHwc1Device->getDisplayAttributes(
+ mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId,
+ ATTRIBUTES_WITH_COLOR, values);
+ if (result != 0) {
+ mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device,
+ mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITHOUT_COLOR, values);
+ hasColor = false;
+ }
+
+ auto attributeMap = hasColor ?
+ ATTRIBUTE_MAP_WITH_COLOR : ATTRIBUTE_MAP_WITHOUT_COLOR;
+
+ newConfig->setAttribute(Attribute::VsyncPeriod,
+ values[attributeMap[HWC_DISPLAY_VSYNC_PERIOD]]);
+ newConfig->setAttribute(Attribute::Width,
+ values[attributeMap[HWC_DISPLAY_WIDTH]]);
+ newConfig->setAttribute(Attribute::Height,
+ values[attributeMap[HWC_DISPLAY_HEIGHT]]);
+ newConfig->setAttribute(Attribute::DpiX,
+ values[attributeMap[HWC_DISPLAY_DPI_X]]);
+ newConfig->setAttribute(Attribute::DpiY,
+ values[attributeMap[HWC_DISPLAY_DPI_Y]]);
+ if (hasColor) {
+ // In HWC1, color modes are referred to as color transforms. To avoid confusion with
+ // the HWC2 concept of color transforms, we internally refer to them as color modes for
+ // both HWC1 and 2.
+ newConfig->setAttribute(ColorMode,
+ values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]);
+ }
+
+ // We can only do this after attempting to read the color mode
+ newConfig->setHwc1Id(hwc1ConfigId);
+
+ for (auto& existingConfig : mConfigs) {
+ if (existingConfig->merge(*newConfig)) {
+ ALOGV("Merged config %d with existing config %u: %s",
+ hwc1ConfigId, existingConfig->getId(),
+ existingConfig->toString().c_str());
+ newConfig.reset();
+ break;
+ }
+ }
+
+ // If it wasn't merged with any existing config, add it to the end
+ if (newConfig) {
+ newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
+ ALOGV("Found new config %u: %s", newConfig->getId(),
+ newConfig->toString().c_str());
+ mConfigs.emplace_back(std::move(newConfig));
+ }
+ }
+
+ initializeActiveConfig();
+ populateColorModes();
+}
+
+void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ mConfigs.emplace_back(std::make_shared<Config>(*this));
+ auto& config = mConfigs[0];
+
+ config->setAttribute(Attribute::Width, static_cast<int32_t>(width));
+ config->setAttribute(Attribute::Height, static_cast<int32_t>(height));
+ config->setHwc1Id(0);
+ config->setId(0);
+ mActiveConfig = config;
+}
+
+bool HWC2On1Adapter::Display::prepare() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ // Only prepare display contents for displays HWC1 knows about
+ if (mHwc1Id == -1) {
+ return true;
+ }
+
+ // It doesn't make sense to prepare a display for which there is no active
+ // config, so return early
+ if (!mActiveConfig) {
+ ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId);
+ return false;
+ }
+
+ allocateRequestedContents();
+ assignHwc1LayerIds();
+
+ mHwc1RequestedContents->retireFenceFd = -1;
+ mHwc1RequestedContents->flags = 0;
+ if (mGeometryChanged) {
+ mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
+ }
+ mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
+ mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
+
+ // +1 is for framebuffer target layer.
+ mHwc1RequestedContents->numHwLayers = mLayers.size() + 1;
+ for (auto& layer : mLayers) {
+ auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
+ hwc1Layer.releaseFenceFd = -1;
+ hwc1Layer.acquireFenceFd = -1;
+ ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
+ layer->applyState(hwc1Layer);
+ }
+
+ prepareFramebufferTarget();
+
+ resetGeometryMarker();
+
+ return true;
+}
+
+void HWC2On1Adapter::Display::generateChanges() {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ mChanges.reset(new Changes);
+
+ size_t numLayers = mHwc1RequestedContents->numHwLayers;
+ for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+ const auto& receivedLayer = mHwc1RequestedContents->hwLayers[hwc1Id];
+ if (mHwc1LayerMap.count(hwc1Id) == 0) {
+ ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
+ "generateChanges: HWC1 layer %zd doesn't have a"
+ " matching HWC2 layer, and isn't the framebuffer target",
+ hwc1Id);
+ continue;
+ }
+
+ Layer& layer = *mHwc1LayerMap[hwc1Id];
+ updateTypeChanges(receivedLayer, layer);
+ updateLayerRequests(receivedLayer, layer);
+ }
+}
+
+bool HWC2On1Adapter::Display::hasChanges() const {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ return mChanges != nullptr;
+}
+
+Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ if (!mChanges || (mChanges->getNumTypes() > 0)) {
+ ALOGE("[%" PRIu64 "] set failed: not validated", mId);
+ return Error::NotValidated;
+ }
+
+ // Set up the client/framebuffer target
+ auto numLayers = hwcContents.numHwLayers;
+
+ // Close acquire fences on FRAMEBUFFER layers, since they will not be used
+ // by HWC
+ for (size_t l = 0; l < numLayers - 1; ++l) {
+ auto& layer = hwcContents.hwLayers[l];
+ if (layer.compositionType == HWC_FRAMEBUFFER) {
+ ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l);
+ close(layer.acquireFenceFd);
+ layer.acquireFenceFd = -1;
+ }
+ }
+
+ auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1];
+ if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) {
+ clientTargetLayer.handle = mClientTarget.getBuffer();
+ clientTargetLayer.acquireFenceFd = mClientTarget.getFence();
+ } else {
+ ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET",
+ mId);
+ }
+
+ mChanges.reset();
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::Display::addRetireFence(int fenceFd) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ mRetireFence.add(fenceFd);
+}
+
+void HWC2On1Adapter::Display::addReleaseFences(
+ const hwc_display_contents_1_t& hwcContents) {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ size_t numLayers = hwcContents.numHwLayers;
+ for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
+ const auto& receivedLayer = hwcContents.hwLayers[hwc1Id];
+ if (mHwc1LayerMap.count(hwc1Id) == 0) {
+ if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) {
+ ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a"
+ " matching HWC2 layer, and isn't the framebuffer"
+ " target", hwc1Id);
+ }
+ // Close the framebuffer target release fence since we will use the
+ // display retire fence instead
+ if (receivedLayer.releaseFenceFd != -1) {
+ close(receivedLayer.releaseFenceFd);
+ }
+ continue;
+ }
+
+ Layer& layer = *mHwc1LayerMap[hwc1Id];
+ ALOGV("Adding release fence %d to layer %" PRIu64,
+ receivedLayer.releaseFenceFd, layer.getId());
+ layer.addReleaseFence(receivedLayer.releaseFenceFd);
+ }
+}
+
+bool HWC2On1Adapter::Display::hasColorTransform() const {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+ return mHasColorTransform;
+}
+
+static std::string hwc1CompositionString(int32_t type) {
+ switch (type) {
+ case HWC_FRAMEBUFFER: return "Framebuffer";
+ case HWC_OVERLAY: return "Overlay";
+ case HWC_BACKGROUND: return "Background";
+ case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget";
+ case HWC_SIDEBAND: return "Sideband";
+ case HWC_CURSOR_OVERLAY: return "CursorOverlay";
+ default:
+ return std::string("Unknown (") + std::to_string(type) + ")";
+ }
+}
+
+static std::string hwc1TransformString(int32_t transform) {
+ switch (transform) {
+ case 0: return "None";
+ case HWC_TRANSFORM_FLIP_H: return "FlipH";
+ case HWC_TRANSFORM_FLIP_V: return "FlipV";
+ case HWC_TRANSFORM_ROT_90: return "Rotate90";
+ case HWC_TRANSFORM_ROT_180: return "Rotate180";
+ case HWC_TRANSFORM_ROT_270: return "Rotate270";
+ case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90";
+ case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90";
+ default:
+ return std::string("Unknown (") + std::to_string(transform) + ")";
+ }
+}
+
+static std::string hwc1BlendModeString(int32_t mode) {
+ switch (mode) {
+ case HWC_BLENDING_NONE: return "None";
+ case HWC_BLENDING_PREMULT: return "Premultiplied";
+ case HWC_BLENDING_COVERAGE: return "Coverage";
+ default:
+ return std::string("Unknown (") + std::to_string(mode) + ")";
+ }
+}
+
+static std::string rectString(hwc_rect_t rect) {
+ std::stringstream output;
+ output << "[" << rect.left << ", " << rect.top << ", ";
+ output << rect.right << ", " << rect.bottom << "]";
+ return output.str();
+}
+
+static std::string approximateFloatString(float f) {
+ if (static_cast<int32_t>(f) == f) {
+ return std::to_string(static_cast<int32_t>(f));
+ }
+ int32_t truncated = static_cast<int32_t>(f * 10);
+ bool approximate = (static_cast<float>(truncated) != f * 10);
+ const size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ auto bytesWritten = snprintf(buffer, BUFFER_SIZE,
+ "%s%.1f", approximate ? "~" : "", f);
+ return std::string(buffer, bytesWritten);
+}
+
+static std::string frectString(hwc_frect_t frect) {
+ std::stringstream output;
+ output << "[" << approximateFloatString(frect.left) << ", ";
+ output << approximateFloatString(frect.top) << ", ";
+ output << approximateFloatString(frect.right) << ", ";
+ output << approximateFloatString(frect.bottom) << "]";
+ return output.str();
+}
+
+static std::string colorString(hwc_color_t color) {
+ std::stringstream output;
+ output << "RGBA [";
+ output << static_cast<int32_t>(color.r) << ", ";
+ output << static_cast<int32_t>(color.g) << ", ";
+ output << static_cast<int32_t>(color.b) << ", ";
+ output << static_cast<int32_t>(color.a) << "]";
+ return output.str();
+}
+
+static std::string alphaString(float f) {
+ const size_t BUFFER_SIZE = 8;
+ char buffer[BUFFER_SIZE] = {};
+ auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
+ return std::string(buffer, bytesWritten);
+}
+
+static std::string to_string(const hwc_layer_1_t& hwcLayer,
+ int32_t hwc1MinorVersion) {
+ const char* fill = " ";
+
+ std::stringstream output;
+
+ output << " Composition: " <<
+ hwc1CompositionString(hwcLayer.compositionType);
+
+ if (hwcLayer.compositionType == HWC_BACKGROUND) {
+ output << " Color: " << colorString(hwcLayer.backgroundColor) << '\n';
+ } else if (hwcLayer.compositionType == HWC_SIDEBAND) {
+ output << " Stream: " << hwcLayer.sidebandStream << '\n';
+ } else {
+ output << " Buffer: " << hwcLayer.handle << "/" <<
+ hwcLayer.acquireFenceFd << '\n';
+ }
+
+ output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) <<
+ '\n';
+
+ output << fill << "Source crop: ";
+ if (hwc1MinorVersion >= 3) {
+ output << frectString(hwcLayer.sourceCropf) << '\n';
+ } else {
+ output << rectString(hwcLayer.sourceCropi) << '\n';
+ }
+
+ output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform);
+ output << " Blend mode: " << hwc1BlendModeString(hwcLayer.blending);
+ if (hwcLayer.planeAlpha != 0xFF) {
+ output << " Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f);
+ }
+ output << '\n';
+
+ if (hwcLayer.hints != 0) {
+ output << fill << "Hints:";
+ if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) {
+ output << " TripleBuffer";
+ }
+ if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) {
+ output << " ClearFB";
+ }
+ output << '\n';
+ }
+
+ if (hwcLayer.flags != 0) {
+ output << fill << "Flags:";
+ if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) {
+ output << " SkipLayer";
+ }
+ if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) {
+ output << " IsCursorLayer";
+ }
+ output << '\n';
+ }
+
+ return output.str();
+}
+
+static std::string to_string(const hwc_display_contents_1_t& hwcContents,
+ int32_t hwc1MinorVersion) {
+ const char* fill = " ";
+
+ std::stringstream output;
+ output << fill << "Geometry changed: " <<
+ ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n");
+
+ output << fill << hwcContents.numHwLayers << " Layer" <<
+ ((hwcContents.numHwLayers == 1) ? "\n" : "s\n");
+ for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) {
+ output << fill << " Layer " << layer;
+ output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion);
+ }
+
+ if (hwcContents.outbuf != nullptr) {
+ output << fill << "Output buffer: " << hwcContents.outbuf << "/" <<
+ hwcContents.outbufAcquireFenceFd << '\n';
+ }
+
+ return output.str();
+}
+
+std::string HWC2On1Adapter::Display::dump() const {
+ std::unique_lock<std::recursive_mutex> lock(mStateMutex);
+
+ std::stringstream output;
+
+ output << " Display " << mId << ": ";
+ output << to_string(mType) << " ";
+ output << "HWC1 ID: " << mHwc1Id << " ";
+ output << "Power mode: " << to_string(mPowerMode) << " ";
+ output << "Vsync: " << to_string(mVsyncEnabled) << '\n';
+
+ output << " Color modes [active]:";
+ for (const auto& mode : mColorModes) {
+ if (mode == mActiveColorMode) {
+ output << " [" << mode << ']';
+ } else {
+ output << " " << mode;
+ }
+ }
+ output << '\n';
+
+ output << " " << mConfigs.size() << " Config" <<
+ (mConfigs.size() == 1 ? "" : "s") << " (* active)\n";
+ for (const auto& config : mConfigs) {
+ output << (config == mActiveConfig ? " * " : " ");
+ output << config->toString(true) << '\n';
+ }
+
+ output << " " << mLayers.size() << " Layer" <<
+ (mLayers.size() == 1 ? "" : "s") << '\n';
+ for (const auto& layer : mLayers) {
+ output << layer->dump();
+ }
+
+ output << " Client target: " << mClientTarget.getBuffer() << '\n';
+
+ if (mOutputBuffer.getBuffer() != nullptr) {
+ output << " Output buffer: " << mOutputBuffer.getBuffer() << '\n';
+ }
+
+ if (mHwc1RequestedContents) {
+ output << " Last requested HWC1 state\n";
+ output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
+ }
+
+ return output.str();
+}
+
+hwc_rect_t* HWC2On1Adapter::Display::GetRects(size_t numRects) {
+ if (numRects == 0) {
+ return nullptr;
+ }
+
+ if (numRects > mNumAvailableRects) {
+ // This should NEVER happen since we calculated how many rects the
+ // display would need.
+ ALOGE("Rect allocation failure! SF is likely to crash soon!");
+ return nullptr;
+
+ }
+ hwc_rect_t* rects = mNextAvailableRect;
+ mNextAvailableRect += numRects;
+ mNumAvailableRects -= numRects;
+ return rects;
+}
+
+hwc_display_contents_1* HWC2On1Adapter::Display::getDisplayContents() {
+ return mHwc1RequestedContents.get();
+}
+
+void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute,
+ int32_t value) {
+ mAttributes[attribute] = value;
+}
+
+int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const {
+ if (mAttributes.count(attribute) == 0) {
+ return -1;
+ }
+ return mAttributes.at(attribute);
+}
+
+void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id) {
+ android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
+ mHwc1Ids.emplace(colorMode, id);
+}
+
+bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const {
+ for (const auto& idPair : mHwc1Ids) {
+ if (id == idPair.second) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Error HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
+ uint32_t id, android_color_mode_t* outMode) const {
+ for (const auto& idPair : mHwc1Ids) {
+ if (id == idPair.second) {
+ *outMode = idPair.first;
+ return Error::None;
+ }
+ }
+ ALOGE("Unable to find color mode for HWC ID %" PRIu32 " on config %u", id, mId);
+ return Error::BadParameter;
+}
+
+Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
+ uint32_t* outId) const {
+ for (const auto& idPair : mHwc1Ids) {
+ if (mode == idPair.first) {
+ *outId = idPair.second;
+ return Error::None;
+ }
+ }
+ ALOGE("Unable to find HWC1 ID for color mode %d on config %u", mode, mId);
+ return Error::BadParameter;
+}
+
+bool HWC2On1Adapter::Display::Config::merge(const Config& other) {
+ auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height,
+ HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX,
+ HWC2::Attribute::DpiY};
+ for (auto attribute : attributes) {
+ if (getAttribute(attribute) != other.getAttribute(attribute)) {
+ return false;
+ }
+ }
+ android_color_mode_t otherColorMode =
+ static_cast<android_color_mode_t>(other.getAttribute(ColorMode));
+ if (mHwc1Ids.count(otherColorMode) != 0) {
+ ALOGE("Attempted to merge two configs (%u and %u) which appear to be "
+ "identical", mHwc1Ids.at(otherColorMode),
+ other.mHwc1Ids.at(otherColorMode));
+ return false;
+ }
+ mHwc1Ids.emplace(otherColorMode,
+ other.mHwc1Ids.at(otherColorMode));
+ return true;
+}
+
+std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const {
+ std::set<android_color_mode_t> colorModes;
+ for (const auto& idPair : mHwc1Ids) {
+ colorModes.emplace(idPair.first);
+ }
+ return colorModes;
+}
+
+std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const {
+ std::string output;
+
+ const size_t BUFFER_SIZE = 100;
+ char buffer[BUFFER_SIZE] = {};
+ auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ "%u x %u", mAttributes.at(HWC2::Attribute::Width),
+ mAttributes.at(HWC2::Attribute::Height));
+ output.append(buffer, writtenBytes);
+
+ if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
+ 1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
+ output.append(buffer, writtenBytes);
+ }
+
+ if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
+ mAttributes.at(HWC2::Attribute::DpiX) != -1) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ ", DPI: %.1f x %.1f",
+ mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
+ mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
+ output.append(buffer, writtenBytes);
+ }
+
+ std::memset(buffer, 0, BUFFER_SIZE);
+ if (splitLine) {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ "\n HWC1 ID/Color transform:");
+ } else {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ ", HWC1 ID/Color transform:");
+ }
+ output.append(buffer, writtenBytes);
+
+
+ for (const auto& id : mHwc1Ids) {
+ android_color_mode_t colorMode = id.first;
+ uint32_t hwc1Id = id.second;
+ std::memset(buffer, 0, BUFFER_SIZE);
+ if (colorMode == mDisplay.mActiveColorMode) {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id,
+ colorMode);
+ } else {
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id,
+ colorMode);
+ }
+ output.append(buffer, writtenBytes);
+ }
+
+ return output;
+}
+
+std::shared_ptr<const HWC2On1Adapter::Display::Config>
+ HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const {
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ return nullptr;
+ }
+ return mConfigs[configId];
+}
+
+void HWC2On1Adapter::Display::populateColorModes() {
+ mColorModes = mConfigs[0]->getColorModes();
+ for (const auto& config : mConfigs) {
+ std::set<android_color_mode_t> intersection;
+ auto configModes = config->getColorModes();
+ std::set_intersection(mColorModes.cbegin(), mColorModes.cend(),
+ configModes.cbegin(), configModes.cend(),
+ std::inserter(intersection, intersection.begin()));
+ std::swap(intersection, mColorModes);
+ }
+}
+
+void HWC2On1Adapter::Display::initializeActiveConfig() {
+ if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
+ ALOGV("getActiveConfig is null, choosing config 0");
+ mActiveConfig = mConfigs[0];
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ return;
+ }
+
+ auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
+ mDevice.mHwc1Device, mHwc1Id);
+
+ // Some devices startup without an activeConfig:
+ // We need to set one ourselves.
+ if (activeConfig == HWC_ERROR) {
+ ALOGV("There is no active configuration: Picking the first one: 0.");
+ const int defaultIndex = 0;
+ mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, defaultIndex);
+ activeConfig = defaultIndex;
+ }
+
+ for (const auto& config : mConfigs) {
+ if (config->hasHwc1Id(activeConfig)) {
+ ALOGE("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig);
+ mActiveConfig = config;
+ if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
+ // This should never happen since we checked for the config's presence before
+ // setting it as active.
+ ALOGE("Unable to find color mode for active HWC1 config %d", config->getId());
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ }
+ break;
+ }
+ }
+ if (!mActiveConfig) {
+ ALOGV("Unable to find active HWC1 config %u, defaulting to "
+ "config 0", activeConfig);
+ mActiveConfig = mConfigs[0];
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ }
+
+
+
+
+}
+
+void HWC2On1Adapter::Display::allocateRequestedContents() {
+ // What needs to be allocated:
+ // 1 hwc_display_contents_1_t
+ // 1 hwc_layer_1_t for each layer
+ // 1 hwc_rect_t for each layer's surfaceDamage
+ // 1 hwc_rect_t for each layer's visibleRegion
+ // 1 hwc_layer_1_t for the framebuffer
+ // 1 hwc_rect_t for the framebuffer's visibleRegion
+
+ // Count # of surfaceDamage
+ size_t numSurfaceDamages = 0;
+ for (const auto& layer : mLayers) {
+ numSurfaceDamages += layer->getNumSurfaceDamages();
+ }
+
+ // Count # of visibleRegions (start at 1 for mandatory framebuffer target
+ // region)
+ size_t numVisibleRegion = 1;
+ for (const auto& layer : mLayers) {
+ numVisibleRegion += layer->getNumVisibleRegions();
+ }
+
+ size_t numRects = numVisibleRegion + numSurfaceDamages;
+ auto numLayers = mLayers.size() + 1;
+ size_t size = sizeof(hwc_display_contents_1_t) +
+ sizeof(hwc_layer_1_t) * numLayers +
+ sizeof(hwc_rect_t) * numRects;
+ auto contents = static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
+ mHwc1RequestedContents.reset(contents);
+ mNextAvailableRect = reinterpret_cast<hwc_rect_t*>(&contents->hwLayers[numLayers]);
+ mNumAvailableRects = numRects;
+}
+
+void HWC2On1Adapter::Display::assignHwc1LayerIds() {
+ mHwc1LayerMap.clear();
+ size_t nextHwc1Id = 0;
+ for (auto& layer : mLayers) {
+ mHwc1LayerMap[nextHwc1Id] = layer;
+ layer->setHwc1Id(nextHwc1Id++);
+ }
+}
+
+void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
+ const Layer& layer) {
+ auto layerId = layer.getId();
+ switch (hwc1Layer.compositionType) {
+ case HWC_FRAMEBUFFER:
+ if (layer.getCompositionType() != Composition::Client) {
+ mChanges->addTypeChange(layerId, Composition::Client);
+ }
+ break;
+ case HWC_OVERLAY:
+ if (layer.getCompositionType() != Composition::Device) {
+ mChanges->addTypeChange(layerId, Composition::Device);
+ }
+ break;
+ case HWC_BACKGROUND:
+ ALOGE_IF(layer.getCompositionType() != Composition::SolidColor,
+ "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2"
+ " wasn't expecting SolidColor");
+ break;
+ case HWC_FRAMEBUFFER_TARGET:
+ // Do nothing, since it shouldn't be modified by HWC1
+ break;
+ case HWC_SIDEBAND:
+ ALOGE_IF(layer.getCompositionType() != Composition::Sideband,
+ "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2"
+ " wasn't expecting Sideband");
+ break;
+ case HWC_CURSOR_OVERLAY:
+ ALOGE_IF(layer.getCompositionType() != Composition::Cursor,
+ "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but"
+ " HWC2 wasn't expecting Cursor");
+ break;
+ }
+}
+
+void HWC2On1Adapter::Display::updateLayerRequests(
+ const hwc_layer_1_t& hwc1Layer, const Layer& layer) {
+ if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
+ mChanges->addLayerRequest(layer.getId(),
+ LayerRequest::ClearClientTarget);
+ }
+}
+
+void HWC2On1Adapter::Display::prepareFramebufferTarget() {
+ // We check that mActiveConfig is valid in Display::prepare
+ int32_t width = mActiveConfig->getAttribute(Attribute::Width);
+ int32_t height = mActiveConfig->getAttribute(Attribute::Height);
+
+ auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()];
+ hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET;
+ hwc1Target.releaseFenceFd = -1;
+ hwc1Target.hints = 0;
+ hwc1Target.flags = 0;
+ hwc1Target.transform = 0;
+ hwc1Target.blending = HWC_BLENDING_PREMULT;
+ if (mDevice.getHwc1MinorVersion() < 3) {
+ hwc1Target.sourceCropi = {0, 0, width, height};
+ } else {
+ hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast<float>(width),
+ static_cast<float>(height)};
+ }
+ hwc1Target.displayFrame = {0, 0, width, height};
+ hwc1Target.planeAlpha = 255;
+
+ hwc1Target.visibleRegionScreen.numRects = 1;
+ hwc_rect_t* rects = GetRects(1);
+ rects[0].left = 0;
+ rects[0].top = 0;
+ rects[0].right = width;
+ rects[0].bottom = height;
+ hwc1Target.visibleRegionScreen.rects = rects;
+
+ // We will set this to the correct value in set
+ hwc1Target.acquireFenceFd = -1;
+}
+
+// Layer functions
+
+std::atomic<hwc2_layer_t> HWC2On1Adapter::Layer::sNextId(1);
+
+HWC2On1Adapter::Layer::Layer(Display& display)
+ : mId(sNextId++),
+ mDisplay(display),
+ mBuffer(),
+ mSurfaceDamage(),
+ mBlendMode(BlendMode::None),
+ mColor({0, 0, 0, 0}),
+ mCompositionType(Composition::Invalid),
+ mDisplayFrame({0, 0, -1, -1}),
+ mPlaneAlpha(0.0f),
+ mSidebandStream(nullptr),
+ mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
+ mTransform(Transform::None),
+ mVisibleRegion(),
+ mZ(0),
+ mReleaseFence(),
+ mHwc1Id(0),
+ mHasUnsupportedPlaneAlpha(false) {}
+
+bool HWC2On1Adapter::SortLayersByZ::operator()(
+ const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs) {
+ return lhs->getZ() < rhs->getZ();
+}
+
+Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer,
+ int32_t acquireFence) {
+ ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
+ mBuffer.setBuffer(buffer);
+ mBuffer.setFence(acquireFence);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y) {
+ if (mCompositionType != Composition::Cursor) {
+ return Error::BadLayer;
+ }
+
+ if (mDisplay.hasChanges()) {
+ return Error::NotValidated;
+ }
+
+ auto displayId = mDisplay.getHwc1Id();
+ auto hwc1Device = mDisplay.getDevice().getHwc1Device();
+ hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y);
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage) {
+ // HWC1 supports surface damage starting only with version 1.5.
+ if (mDisplay.getDevice().mHwc1MinorVersion < 5) {
+ return Error::None;
+ }
+ mSurfaceDamage.resize(damage.numRects);
+ std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
+ return Error::None;
+}
+
+// Layer state functions
+
+Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode) {
+ mBlendMode = mode;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setColor(hwc_color_t color) {
+ mColor = color;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setCompositionType(Composition type) {
+ mCompositionType = type;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t) {
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame) {
+ mDisplayFrame = frame;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha) {
+ mPlaneAlpha = alpha;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream) {
+ mSidebandStream = stream;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop) {
+ mSourceCrop = crop;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setTransform(Transform transform) {
+ mTransform = transform;
+ mDisplay.markGeometryChanged();
+ return Error::None;
+}
+
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ return rect1.left == rect2.left &&
+ rect1.right == rect2.right &&
+ rect1.top == rect2.top &&
+ rect1.bottom == rect2.bottom;
+}
+
+Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
+ if ((getNumVisibleRegions() != visible.numRects) ||
+ !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+ compareRects)) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ mDisplay.markGeometryChanged();
+ }
+ return Error::None;
+}
+
+Error HWC2On1Adapter::Layer::setZ(uint32_t z) {
+ mZ = z;
+ return Error::None;
+}
+
+void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd) {
+ ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
+ mReleaseFence.add(fenceFd);
+}
+
+const sp<MiniFence>& HWC2On1Adapter::Layer::getReleaseFence() const {
+ return mReleaseFence.get();
+}
+
+void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer) {
+ applyCommonState(hwc1Layer);
+ applyCompositionType(hwc1Layer);
+ switch (mCompositionType) {
+ case Composition::SolidColor : applySolidColorState(hwc1Layer); break;
+ case Composition::Sideband : applySidebandState(hwc1Layer); break;
+ default: applyBufferState(hwc1Layer); break;
+ }
+}
+
+static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
+ const std::vector<hwc_rect_t>& surfaceDamage) {
+ std::string regions;
+ regions += " Visible Region";
+ regions.resize(40, ' ');
+ regions += "Surface Damage\n";
+
+ size_t numPrinted = 0;
+ size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size());
+ while (numPrinted < maxSize) {
+ std::string line(" ");
+ if (visibleRegion.empty() && numPrinted == 0) {
+ line += "None";
+ } else if (numPrinted < visibleRegion.size()) {
+ line += rectString(visibleRegion[numPrinted]);
+ }
+ line.resize(40, ' ');
+ if (surfaceDamage.empty() && numPrinted == 0) {
+ line += "None";
+ } else if (numPrinted < surfaceDamage.size()) {
+ line += rectString(surfaceDamage[numPrinted]);
+ }
+ line += '\n';
+ regions += line;
+ ++numPrinted;
+ }
+ return regions;
+}
+
+std::string HWC2On1Adapter::Layer::dump() const {
+ std::stringstream output;
+ const char* fill = " ";
+
+ output << fill << to_string(mCompositionType);
+ output << " Layer HWC2/1: " << mId << "/" << mHwc1Id << " ";
+ output << "Z: " << mZ;
+ if (mCompositionType == HWC2::Composition::SolidColor) {
+ output << " " << colorString(mColor);
+ } else if (mCompositionType == HWC2::Composition::Sideband) {
+ output << " Handle: " << mSidebandStream << '\n';
+ } else {
+ output << " Buffer: " << mBuffer.getBuffer() << '\n';
+ output << fill << " Display frame [LTRB]: " <<
+ rectString(mDisplayFrame) << '\n';
+ output << fill << " Source crop: " <<
+ frectString(mSourceCrop) << '\n';
+ output << fill << " Transform: " << to_string(mTransform);
+ output << " Blend mode: " << to_string(mBlendMode);
+ if (mPlaneAlpha != 1.0f) {
+ output << " Alpha: " <<
+ alphaString(mPlaneAlpha) << '\n';
+ } else {
+ output << '\n';
+ }
+ output << regionStrings(mVisibleRegion, mSurfaceDamage);
+ }
+ return output.str();
+}
+
+static int getHwc1Blending(HWC2::BlendMode blendMode) {
+ switch (blendMode) {
+ case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
+ case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
+ default: return HWC_BLENDING_NONE;
+ }
+}
+
+void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer) {
+ auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
+ hwc1Layer.blending = getHwc1Blending(mBlendMode);
+ hwc1Layer.displayFrame = mDisplayFrame;
+
+ auto pendingAlpha = mPlaneAlpha;
+ if (minorVersion < 2) {
+ mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
+ } else {
+ hwc1Layer.planeAlpha =
+ static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
+ }
+
+ if (minorVersion < 3) {
+ auto pending = mSourceCrop;
+ hwc1Layer.sourceCropi.left =
+ static_cast<int32_t>(std::ceil(pending.left));
+ hwc1Layer.sourceCropi.top =
+ static_cast<int32_t>(std::ceil(pending.top));
+ hwc1Layer.sourceCropi.right =
+ static_cast<int32_t>(std::floor(pending.right));
+ hwc1Layer.sourceCropi.bottom =
+ static_cast<int32_t>(std::floor(pending.bottom));
+ } else {
+ hwc1Layer.sourceCropf = mSourceCrop;
+ }
+
+ hwc1Layer.transform = static_cast<uint32_t>(mTransform);
+
+ auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
+ hwc1VisibleRegion.numRects = mVisibleRegion.size();
+ hwc_rect_t* rects = mDisplay.GetRects(hwc1VisibleRegion.numRects);
+ hwc1VisibleRegion.rects = rects;
+ for (size_t i = 0; i < mVisibleRegion.size(); i++) {
+ rects[i] = mVisibleRegion[i];
+ }
+}
+
+void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer) {
+ // If the device does not support background color it is likely to make
+ // assumption regarding backgroundColor and handle (both fields occupy
+ // the same location in hwc_layer_1_t union).
+ // To not confuse these devices we don't set background color and we
+ // make sure handle is a null pointer.
+ if (hasUnsupportedBackgroundColor()) {
+ hwc1Layer.handle = nullptr;
+ } else {
+ hwc1Layer.backgroundColor = mColor;
+ }
+}
+
+void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer) {
+ hwc1Layer.sidebandStream = mSidebandStream;
+}
+
+void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) {
+ hwc1Layer.handle = mBuffer.getBuffer();
+ hwc1Layer.acquireFenceFd = mBuffer.getFence();
+}
+
+void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer) {
+ // HWC1 never supports color transforms or dataspaces and only sometimes
+ // supports plane alpha (depending on the version). These require us to drop
+ // some or all layers to client composition.
+ if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
+ hasUnsupportedBackgroundColor()) {
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ hwc1Layer.flags = 0;
+ switch (mCompositionType) {
+ case Composition::Client:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Device:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ break;
+ case Composition::SolidColor:
+ // In theory the following line should work, but since the HWC1
+ // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
+ // devices may not work correctly. To be on the safe side, we
+ // fall back to client composition.
+ //
+ // hwc1Layer.compositionType = HWC_BACKGROUND;
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ case Composition::Cursor:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
+ hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
+ }
+ break;
+ case Composition::Sideband:
+ if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
+ hwc1Layer.compositionType = HWC_SIDEBAND;
+ } else {
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ }
+ break;
+ default:
+ hwc1Layer.compositionType = HWC_FRAMEBUFFER;
+ hwc1Layer.flags |= HWC_SKIP_LAYER;
+ break;
+ }
+ ALOGV("Layer %" PRIu64 " %s set to %d", mId,
+ to_string(mCompositionType).c_str(),
+ hwc1Layer.compositionType);
+ ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, " and skipping");
+}
+
+// Adapter helpers
+
+void HWC2On1Adapter::populateCapabilities() {
+ if (mHwc1MinorVersion >= 3U) {
+ int supportedTypes = 0;
+ auto result = mHwc1Device->query(mHwc1Device,
+ HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
+ if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL_BIT) != 0)) {
+ ALOGI("Found support for HWC virtual displays");
+ mHwc1SupportsVirtualDisplays = true;
+ }
+ }
+ if (mHwc1MinorVersion >= 4U) {
+ mCapabilities.insert(Capability::SidebandStream);
+ }
+
+ // Check for HWC background color layer support.
+ if (mHwc1MinorVersion >= 1U) {
+ int backgroundColorSupported = 0;
+ auto result = mHwc1Device->query(mHwc1Device,
+ HWC_BACKGROUND_LAYER_SUPPORTED,
+ &backgroundColorSupported);
+ if ((result == 0) && (backgroundColorSupported == 1)) {
+ ALOGV("Found support for HWC background color");
+ mHwc1SupportsBackgroundColor = true;
+ }
+ }
+
+ // Some devices might have HWC1 retire fences that accurately emulate
+ // HWC2 present fences when they are deferred, but it's not very reliable.
+ // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
+ mCapabilities.insert(Capability::PresentFenceIsNotReliable);
+}
+
+HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ auto display = mDisplays.find(id);
+ if (display == mDisplays.end()) {
+ return nullptr;
+ }
+
+ return display->second.get();
+}
+
+std::tuple<HWC2On1Adapter::Layer*, Error> HWC2On1Adapter::getLayer(
+ hwc2_display_t displayId, hwc2_layer_t layerId) {
+ auto display = getDisplay(displayId);
+ if (!display) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
+ }
+
+ auto layerEntry = mLayers.find(layerId);
+ if (layerEntry == mLayers.end()) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+
+ auto layer = layerEntry->second;
+ if (layer->getDisplay().getId() != displayId) {
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+ return std::make_tuple(layer.get(), Error::None);
+}
+
+void HWC2On1Adapter::populatePrimary() {
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+ mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
+ display->setHwc1Id(HWC_DISPLAY_PRIMARY);
+ display->populateConfigs();
+ mDisplays.emplace(display->getId(), std::move(display));
+}
+
+bool HWC2On1Adapter::prepareAllDisplays() {
+ ATRACE_CALL();
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ for (const auto& displayPair : mDisplays) {
+ auto& display = displayPair.second;
+ if (!display->prepare()) {
+ return false;
+ }
+ }
+
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
+ ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
+ return false;
+ }
+
+ // Build an array of hwc_display_contents_1 to call prepare() on HWC1.
+ mHwc1Contents.clear();
+
+ // Always push the primary display
+ auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
+ auto& primaryDisplay = mDisplays[primaryDisplayId];
+ mHwc1Contents.push_back(primaryDisplay->getDisplayContents());
+
+ // Push the external display, if present
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
+ auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
+ auto& externalDisplay = mDisplays[externalDisplayId];
+ mHwc1Contents.push_back(externalDisplay->getDisplayContents());
+ } else {
+ // Even if an external display isn't present, we still need to send
+ // at least two displays down to HWC1
+ mHwc1Contents.push_back(nullptr);
+ }
+
+ // Push the hardware virtual display, if supported and present
+ if (mHwc1MinorVersion >= 3) {
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
+ auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
+ auto& virtualDisplay = mDisplays[virtualDisplayId];
+ mHwc1Contents.push_back(virtualDisplay->getDisplayContents());
+ } else {
+ mHwc1Contents.push_back(nullptr);
+ }
+ }
+
+ for (auto& displayContents : mHwc1Contents) {
+ if (!displayContents) {
+ continue;
+ }
+
+ ALOGV("Display %zd layers:", mHwc1Contents.size() - 1);
+ for (size_t l = 0; l < displayContents->numHwLayers; ++l) {
+ auto& layer = displayContents->hwLayers[l];
+ ALOGV(" %zd: %d", l, layer.compositionType);
+ }
+ }
+
+ ALOGV("Calling HWC1 prepare");
+ {
+ ATRACE_NAME("HWC1 prepare");
+ mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(),
+ mHwc1Contents.data());
+ }
+
+ for (size_t c = 0; c < mHwc1Contents.size(); ++c) {
+ auto& contents = mHwc1Contents[c];
+ if (!contents) {
+ continue;
+ }
+ ALOGV("Display %zd layers:", c);
+ for (size_t l = 0; l < contents->numHwLayers; ++l) {
+ ALOGV(" %zd: %d", l, contents->hwLayers[l].compositionType);
+ }
+ }
+
+ // Return the received contents to their respective displays
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ display->generateChanges();
+ }
+
+ return true;
+}
+
+void dumpHWC1Message(hwc_composer_device_1* device, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ ALOGV("*****************************");
+ size_t displayId = 0;
+ while (displayId < numDisplays) {
+ hwc_display_contents_1_t* display = displays[displayId];
+
+ ALOGV("hwc_display_contents_1_t[%zu] @0x%p", displayId, display);
+ if (display == nullptr) {
+ displayId++;
+ continue;
+ }
+ ALOGV(" retirefd:0x%08x", display->retireFenceFd);
+ ALOGV(" outbuf :0x%p", display->outbuf);
+ ALOGV(" outbuffd:0x%08x", display->outbufAcquireFenceFd);
+ ALOGV(" flags :0x%08x", display->flags);
+ for(size_t layerId=0 ; layerId < display->numHwLayers ; layerId++) {
+ hwc_layer_1_t& layer = display->hwLayers[layerId];
+ ALOGV(" Layer[%zu]:", layerId);
+ ALOGV(" composition : 0x%08x", layer.compositionType);
+ ALOGV(" hints : 0x%08x", layer.hints);
+ ALOGV(" flags : 0x%08x", layer.flags);
+ ALOGV(" handle : 0x%p", layer.handle);
+ ALOGV(" transform : 0x%08x", layer.transform);
+ ALOGV(" blending : 0x%08x", layer.blending);
+ ALOGV(" sourceCropf : %f, %f, %f, %f",
+ layer.sourceCropf.left,
+ layer.sourceCropf.top,
+ layer.sourceCropf.right,
+ layer.sourceCropf.bottom);
+ ALOGV(" displayFrame : %d, %d, %d, %d",
+ layer.displayFrame.left,
+ layer.displayFrame.left,
+ layer.displayFrame.left,
+ layer.displayFrame.left);
+ hwc_region_t& visReg = layer.visibleRegionScreen;
+ ALOGV(" visibleRegionScreen: #0x%08zx[@0x%p]",
+ visReg.numRects,
+ visReg.rects);
+ for (size_t visRegId=0; visRegId < visReg.numRects ; visRegId++) {
+ if (layer.visibleRegionScreen.rects == nullptr) {
+ ALOGV(" null");
+ } else {
+ ALOGV(" visibleRegionScreen[%zu] %d, %d, %d, %d",
+ visRegId,
+ visReg.rects[visRegId].left,
+ visReg.rects[visRegId].top,
+ visReg.rects[visRegId].right,
+ visReg.rects[visRegId].bottom);
+ }
+ }
+ ALOGV(" acquireFenceFd : 0x%08x", layer.acquireFenceFd);
+ ALOGV(" releaseFenceFd : 0x%08x", layer.releaseFenceFd);
+ ALOGV(" planeAlpha : 0x%08x", layer.planeAlpha);
+ if (getMinorVersion(device) < 5)
+ continue;
+ ALOGV(" surfaceDamage : #0x%08zx[@0x%p]",
+ layer.surfaceDamage.numRects,
+ layer.surfaceDamage.rects);
+ for (size_t sdId=0; sdId < layer.surfaceDamage.numRects ; sdId++) {
+ if (layer.surfaceDamage.rects == nullptr) {
+ ALOGV(" null");
+ } else {
+ ALOGV(" surfaceDamage[%zu] %d, %d, %d, %d",
+ sdId,
+ layer.surfaceDamage.rects[sdId].left,
+ layer.surfaceDamage.rects[sdId].top,
+ layer.surfaceDamage.rects[sdId].right,
+ layer.surfaceDamage.rects[sdId].bottom);
+ }
+ }
+ }
+ displayId++;
+ }
+ ALOGV("-----------------------------");
+}
+
+Error HWC2On1Adapter::setAllDisplays() {
+ ATRACE_CALL();
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // Make sure we're ready to validate
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ Error error = display->set(*mHwc1Contents[hwc1Id]);
+ if (error != Error::None) {
+ ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id,
+ to_string(error).c_str());
+ return error;
+ }
+ }
+
+ ALOGV("Calling HWC1 set");
+ {
+ ATRACE_NAME("HWC1 set");
+ //dumpHWC1Message(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data());
+ mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
+ mHwc1Contents.data());
+ }
+
+ // Add retire and release fences
+ for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
+ if (mHwc1Contents[hwc1Id] == nullptr) {
+ continue;
+ }
+
+ auto displayId = mHwc1DisplayMap[hwc1Id];
+ auto& display = mDisplays[displayId];
+ auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd;
+ ALOGV("setAllDisplays: Adding retire fence %d to display %zd",
+ retireFenceFd, hwc1Id);
+ display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd);
+ display->addReleaseFences(*mHwc1Contents[hwc1Id]);
+ }
+
+ return Error::None;
+}
+
+void HWC2On1Adapter::hwc1Invalidate() {
+ ALOGV("Received hwc1Invalidate");
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered.
+ if (mCallbacks.count(Callback::Refresh) == 0) {
+ mHasPendingInvalidate = true;
+ return;
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Refresh];
+ std::vector<hwc2_display_t> displays;
+ for (const auto& displayPair : mDisplays) {
+ displays.emplace_back(displayPair.first);
+ }
+
+ // Call back without the state lock held.
+ lock.unlock();
+
+ auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
+ for (auto display : displays) {
+ refresh(callbackInfo.data, display);
+ }
+}
+
+void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) {
+ ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered.
+ if (mCallbacks.count(Callback::Vsync) == 0) {
+ mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
+ return;
+ }
+
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);
+ return;
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Vsync];
+ auto displayId = mHwc1DisplayMap[hwc1DisplayId];
+
+ // Call back without the state lock held.
+ lock.unlock();
+
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
+ vsync(callbackInfo.data, displayId, timestamp);
+}
+
+void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
+ ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
+
+ if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
+ ALOGE("hwc1Hotplug: Received hotplug for non-external display");
+ return;
+ }
+
+ std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
+
+ // If the HWC2-side callback hasn't been registered yet, buffer this until
+ // it is registered
+ if (mCallbacks.count(Callback::Hotplug) == 0) {
+ mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
+ return;
+ }
+
+ hwc2_display_t displayId = UINT64_MAX;
+ if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
+ if (connected == 0) {
+ ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
+ return;
+ }
+
+ // Create a new display on connect
+ auto display = std::make_shared<HWC2On1Adapter::Display>(*this,
+ HWC2::DisplayType::Physical);
+ display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
+ display->populateConfigs();
+ displayId = display->getId();
+ mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
+ mDisplays.emplace(displayId, std::move(display));
+ } else {
+ if (connected != 0) {
+ ALOGW("hwc1Hotplug: Received connect for previously connected "
+ "display");
+ return;
+ }
+
+ // Disconnect an existing display
+ displayId = mHwc1DisplayMap[hwc1DisplayId];
+ mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
+ mDisplays.erase(displayId);
+ }
+
+ const auto& callbackInfo = mCallbacks[Callback::Hotplug];
+
+ // Call back without the state lock held
+ lock.unlock();
+
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
+ auto hwc2Connected = (connected == 0) ?
+ HWC2::Connection::Disconnected : HWC2::Connection::Connected;
+ hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
+}
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp b/graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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 "hwc2on1adapter/MiniFence.h"
+
+#include <unistd.h>
+
+namespace android {
+
+const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+
+MiniFence::MiniFence() :
+ mFenceFd(-1) {
+}
+
+MiniFence::MiniFence(int fenceFd) :
+ mFenceFd(fenceFd) {
+}
+
+MiniFence::~MiniFence() {
+ if (mFenceFd != -1) {
+ close(mFenceFd);
+ }
+}
+
+int MiniFence::dup() const {
+ return ::dup(mFenceFd);
+}
+}
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h b/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * Copyright 2015 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_SF_HWC2_ON_1_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "MiniFence.h"
+
+#include <atomic>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+struct hwc_composer_device_1;
+struct hwc_display_contents_1;
+struct hwc_layer_1;
+
+namespace android {
+
+// For devices unable to provide an implementation of HWC2 (see hwcomposer2.h),
+// we provide an adapter able to talk to HWC1 (see hwcomposer.h). It translates
+// streamed function calls ala HWC2 model to batched array of structs calls ala
+// HWC1 model.
+class HWC2On1Adapter : public hwc2_device_t
+{
+public:
+ explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
+ ~HWC2On1Adapter();
+
+ struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
+ uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
+
+private:
+ static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) {
+ return static_cast<HWC2On1Adapter*>(device);
+ }
+
+ // getCapabilities
+
+ void doGetCapabilities(uint32_t* outCount,
+ int32_t* /*hwc2_capability_t*/ outCapabilities);
+ static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
+ int32_t* /*hwc2_capability_t*/ outCapabilities) {
+ getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+ }
+
+ bool supportsBackgroundColor() {
+ return mHwc1SupportsBackgroundColor;
+ }
+
+ // getFunction
+
+ hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
+ static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
+ int32_t intDesc) {
+ auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
+ return getAdapter(device)->doGetFunction(descriptor);
+ }
+
+ // Device functions
+
+ HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
+ hwc2_display_t* outDisplay);
+ static int32_t createVirtualDisplayHook(hwc2_device_t* device,
+ uint32_t width, uint32_t height, int32_t* /*format*/,
+ hwc2_display_t* outDisplay) {
+ // HWC1 implementations cannot override the buffer format requested by
+ // the consumer
+ auto error = getAdapter(device)->createVirtualDisplay(width, height,
+ outDisplay);
+ return static_cast<int32_t>(error);
+ }
+
+ HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
+ static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
+ hwc2_display_t display) {
+ auto error = getAdapter(device)->destroyVirtualDisplay(display);
+ return static_cast<int32_t>(error);
+ }
+
+ std::string mDumpString;
+ void dump(uint32_t* outSize, char* outBuffer);
+ static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
+ char* outBuffer) {
+ getAdapter(device)->dump(outSize, outBuffer);
+ }
+
+ uint32_t getMaxVirtualDisplayCount();
+ static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
+ return getAdapter(device)->getMaxVirtualDisplayCount();
+ }
+
+ HWC2::Error registerCallback(HWC2::Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
+ static int32_t registerCallbackHook(hwc2_device_t* device,
+ int32_t intDesc, hwc2_callback_data_t callbackData,
+ hwc2_function_pointer_t pointer) {
+ auto descriptor = static_cast<HWC2::Callback>(intDesc);
+ auto error = getAdapter(device)->registerCallback(descriptor,
+ callbackData, pointer);
+ return static_cast<int32_t>(error);
+ }
+
+ // Display functions
+
+ class Layer;
+
+ class SortLayersByZ {
+ public:
+ bool operator()(const std::shared_ptr<Layer>& lhs,
+ const std::shared_ptr<Layer>& rhs);
+ };
+
+ // The semantics of the fences returned by the device differ between
+ // hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
+ // for more information.
+ //
+ // Release fences in hwc1 are obtained on set() for a frame n and signaled
+ // when the layer buffer is not needed for read operations anymore
+ // (typically on frame n+1). In HWC2, release fences are obtained with a
+ // special call after present() for frame n. These fences signal
+ // on frame n: More specifically, the fence for a given buffer provided in
+ // frame n will signal when the prior buffer is no longer required.
+ //
+ // A retire fence (HWC1) is signaled when a composition is replaced
+ // on the panel whereas a present fence (HWC2) is signaled when a
+ // composition starts to be displayed on a panel.
+ //
+ // The HWC2to1Adapter emulates the new fence semantics for a frame
+ // n by returning the fence from frame n-1. For frame 0, the adapter
+ // returns NO_FENCE.
+ class DeferredFence {
+ public:
+ DeferredFence()
+ : mFences({MiniFence::NO_FENCE, MiniFence::NO_FENCE}) {}
+
+ void add(int32_t fenceFd) {
+ mFences.emplace(new MiniFence(fenceFd));
+ mFences.pop();
+ }
+
+ const sp<MiniFence>& get() const {
+ return mFences.front();
+ }
+
+ private:
+ // There are always two fences in this queue.
+ std::queue<sp<MiniFence>> mFences;
+ };
+
+ class FencedBuffer {
+ public:
+ FencedBuffer() : mBuffer(nullptr), mFence(MiniFence::NO_FENCE) {}
+
+ void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
+ void setFence(int fenceFd) { mFence = new MiniFence(fenceFd); }
+
+ buffer_handle_t getBuffer() const { return mBuffer; }
+ int getFence() const { return mFence->dup(); }
+
+ private:
+ buffer_handle_t mBuffer;
+ sp<MiniFence> mFence;
+ };
+
+ class Display {
+ public:
+ Display(HWC2On1Adapter& device, HWC2::DisplayType type);
+
+ hwc2_display_t getId() const { return mId; }
+ HWC2On1Adapter& getDevice() const { return mDevice; }
+
+ // Does not require locking because it is set before adding the
+ // Displays to the Adapter's list of displays
+ void setHwc1Id(int32_t id) { mHwc1Id = id; }
+ int32_t getHwc1Id() const { return mHwc1Id; }
+
+ // HWC2 Display functions
+ HWC2::Error acceptChanges();
+ HWC2::Error createLayer(hwc2_layer_t* outLayerId);
+ HWC2::Error destroyLayer(hwc2_layer_t layerId);
+ HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
+ HWC2::Error getAttribute(hwc2_config_t configId,
+ HWC2::Attribute attribute, int32_t* outValue);
+ HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outTypes);
+ HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes);
+ HWC2::Error getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigIds);
+ HWC2::Error getDozeSupport(int32_t* outSupport);
+ HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
+ int32_t* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance);
+ HWC2::Error getName(uint32_t* outSize, char* outName);
+ HWC2::Error getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* outLayers, int32_t* outFences);
+ HWC2::Error getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests);
+ HWC2::Error getType(int32_t* outType);
+
+ // Since HWC1 "presents" (called "set" in HWC1) all Displays
+ // at once, the first call to any Display::present will trigger
+ // present() on all Displays in the Device. Subsequent calls without
+ // first calling validate() are noop (except for duping/returning
+ // the retire fence).
+ HWC2::Error present(int32_t* outRetireFence);
+
+ HWC2::Error setActiveConfig(hwc2_config_t configId);
+ HWC2::Error setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace,
+ hwc_region_t damage);
+ HWC2::Error setColorMode(android_color_mode_t mode);
+ HWC2::Error setColorTransform(android_color_transform_t hint);
+ HWC2::Error setOutputBuffer(buffer_handle_t buffer,
+ int32_t releaseFence);
+ HWC2::Error setPowerMode(HWC2::PowerMode mode);
+ HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
+
+ // Since HWC1 "validates" (called "prepare" in HWC1) all Displays
+ // at once, the first call to any Display::validate() will trigger
+ // validate() on all other Displays in the Device.
+ HWC2::Error validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests);
+
+ HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
+
+ HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
+ int32_t format, int32_t dataspace);
+
+ // Read configs from HWC1 device
+ void populateConfigs();
+
+ // Set configs for a virtual display
+ void populateConfigs(uint32_t width, uint32_t height);
+
+ bool prepare();
+
+ // Called after hwc.prepare() with responses from the device.
+ void generateChanges();
+
+ bool hasChanges() const;
+ HWC2::Error set(hwc_display_contents_1& hwcContents);
+ void addRetireFence(int fenceFd);
+ void addReleaseFences(const hwc_display_contents_1& hwcContents);
+
+ bool hasColorTransform() const;
+
+ std::string dump() const;
+
+ // Return a rect from the pool allocated during validate()
+ hwc_rect_t* GetRects(size_t numRects);
+
+ hwc_display_contents_1* getDisplayContents();
+
+ void markGeometryChanged() { mGeometryChanged = true; }
+ void resetGeometryMarker() { mGeometryChanged = false;}
+ private:
+ class Config {
+ public:
+ Config(Display& display)
+ : mDisplay(display),
+ mId(0),
+ mAttributes() {}
+
+ bool isOnDisplay(const Display& display) const {
+ return display.getId() == mDisplay.getId();
+ }
+
+ void setAttribute(HWC2::Attribute attribute, int32_t value);
+ int32_t getAttribute(HWC2::Attribute attribute) const;
+
+ void setHwc1Id(uint32_t id);
+ bool hasHwc1Id(uint32_t id) const;
+ HWC2::Error getColorModeForHwc1Id(uint32_t id,
+ android_color_mode_t *outMode) const;
+ HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
+ uint32_t* outId) const;
+
+ void setId(hwc2_config_t id) { mId = id; }
+ hwc2_config_t getId() const { return mId; }
+
+ // Attempts to merge two configs that differ only in color
+ // mode. Returns whether the merge was successful
+ bool merge(const Config& other);
+
+ std::set<android_color_mode_t> getColorModes() const;
+
+ // splitLine divides the output into two lines suitable for
+ // dumpsys SurfaceFlinger
+ std::string toString(bool splitLine = false) const;
+
+ private:
+ Display& mDisplay;
+ hwc2_config_t mId;
+ std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
+
+ // Maps from color transform to HWC1 config ID
+ std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
+ };
+
+ // Stores changes requested from the device upon calling prepare().
+ // Handles change request to:
+ // - Layer composition type.
+ // - Layer hints.
+ class Changes {
+ public:
+ uint32_t getNumTypes() const {
+ return static_cast<uint32_t>(mTypeChanges.size());
+ }
+
+ uint32_t getNumLayerRequests() const {
+ return static_cast<uint32_t>(mLayerRequests.size());
+ }
+
+ const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
+ getTypeChanges() const {
+ return mTypeChanges;
+ }
+
+ const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
+ getLayerRequests() const {
+ return mLayerRequests;
+ }
+
+ void addTypeChange(hwc2_layer_t layerId,
+ HWC2::Composition type) {
+ mTypeChanges.insert({layerId, type});
+ }
+
+ void clearTypeChanges() { mTypeChanges.clear(); }
+
+ void addLayerRequest(hwc2_layer_t layerId,
+ HWC2::LayerRequest request) {
+ mLayerRequests.insert({layerId, request});
+ }
+
+ private:
+ std::unordered_map<hwc2_layer_t, HWC2::Composition>
+ mTypeChanges;
+ std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
+ mLayerRequests;
+ };
+
+ std::shared_ptr<const Config>
+ getConfig(hwc2_config_t configId) const;
+
+ void populateColorModes();
+ void initializeActiveConfig();
+
+ // Creates a bi-directional mapping between index in HWC1
+ // prepare/set array and Layer object. Stores mapping in
+ // mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
+ void assignHwc1LayerIds();
+
+ // Called after a response to prepare() has been received:
+ // Ingest composition type changes requested by the device.
+ void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
+ const Layer& layer);
+
+ // Called after a response to prepare() has been received:
+ // Ingest layer hint changes requested by the device.
+ void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
+ const Layer& layer);
+
+ // Set all fields in HWC1 comm array for layer containing the
+ // HWC_FRAMEBUFFER_TARGET (always the last layer).
+ void prepareFramebufferTarget();
+
+ // Display ID generator.
+ static std::atomic<hwc2_display_t> sNextId;
+ const hwc2_display_t mId;
+
+
+ HWC2On1Adapter& mDevice;
+
+ // The state of this display should only be modified from
+ // SurfaceFlinger's main loop, with the exception of when dump is
+ // called. To prevent a bad state from crashing us during a dump
+ // call, all public calls into Display must acquire this mutex.
+ //
+ // It is recursive because we don't want to deadlock in validate
+ // (or present) when we call HWC2On1Adapter::prepareAllDisplays
+ // (or setAllDisplays), which calls back into Display functions
+ // which require locking.
+ mutable std::recursive_mutex mStateMutex;
+
+ // Allocate RAM able to store all layers and rects used for
+ // communication with HWC1. Place allocated RAM in variable
+ // mHwc1RequestedContents.
+ void allocateRequestedContents();
+
+ // Array of structs exchanged between client and hwc1 device.
+ // Sent to device upon calling prepare().
+ std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
+ private:
+ DeferredFence mRetireFence;
+
+ // Will only be non-null after the Display has been validated and
+ // before it has been presented
+ std::unique_ptr<Changes> mChanges;
+
+ int32_t mHwc1Id;
+
+ std::vector<std::shared_ptr<Config>> mConfigs;
+ std::shared_ptr<const Config> mActiveConfig;
+ std::set<android_color_mode_t> mColorModes;
+ android_color_mode_t mActiveColorMode;
+ std::string mName;
+ HWC2::DisplayType mType;
+ HWC2::PowerMode mPowerMode;
+ HWC2::Vsync mVsyncEnabled;
+
+ // Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
+ FencedBuffer mClientTarget;
+
+
+ FencedBuffer mOutputBuffer;
+
+ bool mHasColorTransform;
+
+ // All layers this Display is aware of.
+ std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
+
+ // Mapping between layer index in array of hwc_display_contents_1*
+ // passed to HWC1 during validate/set and Layer object.
+ std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
+
+ // All communication with HWC1 via prepare/set is done with one
+ // alloc. This pointer is pointing to a pool of hwc_rect_t.
+ size_t mNumAvailableRects;
+ hwc_rect_t* mNextAvailableRect;
+
+ // True if any of the Layers contained in this Display have been
+ // updated with anything other than a buffer since last call to
+ // Display::set()
+ bool mGeometryChanged;
+ };
+
+ // Utility template calling a Display object method directly based on the
+ // hwc2_display_t displayId parameter.
+ template <typename ...Args>
+ static int32_t callDisplayFunction(hwc2_device_t* device,
+ hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
+ Args... args) {
+ auto display = getAdapter(device)->getDisplay(displayId);
+ if (!display) {
+ return static_cast<int32_t>(HWC2::Error::BadDisplay);
+ }
+ auto error = ((*display).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
+ Args... args) {
+ return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc,
+ std::forward<Args>(args)...);
+ }
+
+ static int32_t getDisplayAttributeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_config_t config,
+ int32_t intAttribute, int32_t* outValue) {
+ auto attribute = static_cast<HWC2::Attribute>(intAttribute);
+ return callDisplayFunction(device, display, &Display::getAttribute,
+ config, attribute, outValue);
+ }
+
+ static int32_t setColorTransformHook(hwc2_device_t* device,
+ hwc2_display_t display, const float* /*matrix*/,
+ int32_t /*android_color_transform_t*/ intHint) {
+ // We intentionally throw away the matrix, because if the hint is
+ // anything other than IDENTITY, we have to fall back to client
+ // composition anyway
+ auto hint = static_cast<android_color_transform_t>(intHint);
+ return callDisplayFunction(device, display, &Display::setColorTransform,
+ hint);
+ }
+
+ static int32_t setColorModeHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
+ auto mode = static_cast<android_color_mode_t>(intMode);
+ return callDisplayFunction(device, display, &Display::setColorMode,
+ mode);
+ }
+
+ static int32_t setPowerModeHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t intMode) {
+ auto mode = static_cast<HWC2::PowerMode>(intMode);
+ return callDisplayFunction(device, display, &Display::setPowerMode,
+ mode);
+ }
+
+ static int32_t setVsyncEnabledHook(hwc2_device_t* device,
+ hwc2_display_t display, int32_t intEnabled) {
+ auto enabled = static_cast<HWC2::Vsync>(intEnabled);
+ return callDisplayFunction(device, display, &Display::setVsyncEnabled,
+ enabled);
+ }
+
+ class Layer {
+ public:
+ explicit Layer(Display& display);
+
+ bool operator==(const Layer& other) { return mId == other.mId; }
+ bool operator!=(const Layer& other) { return !(*this == other); }
+
+ hwc2_layer_t getId() const { return mId; }
+ Display& getDisplay() const { return mDisplay; }
+
+ // HWC2 Layer functions
+ HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
+ HWC2::Error setCursorPosition(int32_t x, int32_t y);
+ HWC2::Error setSurfaceDamage(hwc_region_t damage);
+
+ // HWC2 Layer state functions
+ HWC2::Error setBlendMode(HWC2::BlendMode mode);
+ HWC2::Error setColor(hwc_color_t color);
+ HWC2::Error setCompositionType(HWC2::Composition type);
+ HWC2::Error setDataspace(android_dataspace_t dataspace);
+ HWC2::Error setDisplayFrame(hwc_rect_t frame);
+ HWC2::Error setPlaneAlpha(float alpha);
+ HWC2::Error setSidebandStream(const native_handle_t* stream);
+ HWC2::Error setSourceCrop(hwc_frect_t crop);
+ HWC2::Error setTransform(HWC2::Transform transform);
+ HWC2::Error setVisibleRegion(hwc_region_t visible);
+ HWC2::Error setZ(uint32_t z);
+
+ HWC2::Composition getCompositionType() const {
+ return mCompositionType;
+ }
+ uint32_t getZ() const { return mZ; }
+
+ void addReleaseFence(int fenceFd);
+ const sp<MiniFence>& getReleaseFence() const;
+
+ void setHwc1Id(size_t id) { mHwc1Id = id; }
+ size_t getHwc1Id() const { return mHwc1Id; }
+
+ // Write state to HWC1 communication struct.
+ void applyState(struct hwc_layer_1& hwc1Layer);
+
+ std::string dump() const;
+
+ std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
+
+ std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
+
+ // True if a layer cannot be properly rendered by the device due
+ // to usage of SolidColor (a.k.a BackgroundColor in HWC1).
+ bool hasUnsupportedBackgroundColor() {
+ return (mCompositionType == HWC2::Composition::SolidColor &&
+ !mDisplay.getDevice().supportsBackgroundColor());
+ }
+ private:
+ void applyCommonState(struct hwc_layer_1& hwc1Layer);
+ void applySolidColorState(struct hwc_layer_1& hwc1Layer);
+ void applySidebandState(struct hwc_layer_1& hwc1Layer);
+ void applyBufferState(struct hwc_layer_1& hwc1Layer);
+ void applyCompositionType(struct hwc_layer_1& hwc1Layer);
+
+ static std::atomic<hwc2_layer_t> sNextId;
+ const hwc2_layer_t mId;
+ Display& mDisplay;
+
+ FencedBuffer mBuffer;
+ std::vector<hwc_rect_t> mSurfaceDamage;
+
+ HWC2::BlendMode mBlendMode;
+ hwc_color_t mColor;
+ HWC2::Composition mCompositionType;
+ hwc_rect_t mDisplayFrame;
+ float mPlaneAlpha;
+ const native_handle_t* mSidebandStream;
+ hwc_frect_t mSourceCrop;
+ HWC2::Transform mTransform;
+ std::vector<hwc_rect_t> mVisibleRegion;
+
+ uint32_t mZ;
+
+ DeferredFence mReleaseFence;
+
+ size_t mHwc1Id;
+ bool mHasUnsupportedPlaneAlpha;
+ };
+
+ // Utility tempate calling a Layer object method based on ID parameters:
+ // hwc2_display_t displayId
+ // and
+ // hwc2_layer_t layerId
+ template <typename ...Args>
+ static int32_t callLayerFunction(hwc2_device_t* device,
+ hwc2_display_t displayId, hwc2_layer_t layerId,
+ HWC2::Error (Layer::*member)(Args...), Args... args) {
+ auto result = getAdapter(device)->getLayer(displayId, layerId);
+ auto error = std::get<HWC2::Error>(result);
+ if (error == HWC2::Error::None) {
+ auto layer = std::get<Layer*>(result);
+ error = ((*layer).*member)(std::forward<Args>(args)...);
+ }
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
+ hwc2_layer_t layerId, Args... args) {
+ return HWC2On1Adapter::callLayerFunction(device, displayId, layerId,
+ memFunc, std::forward<Args>(args)...);
+ }
+
+ // Layer state functions
+
+ static int32_t setLayerBlendModeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
+ auto mode = static_cast<HWC2::BlendMode>(intMode);
+ return callLayerFunction(device, display, layer,
+ &Layer::setBlendMode, mode);
+ }
+
+ static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
+ auto type = static_cast<HWC2::Composition>(intType);
+ return callLayerFunction(device, display, layer,
+ &Layer::setCompositionType, type);
+ }
+
+ static int32_t setLayerDataspaceHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) {
+ auto dataspace = static_cast<android_dataspace_t>(intDataspace);
+ return callLayerFunction(device, display, layer, &Layer::setDataspace,
+ dataspace);
+ }
+
+ static int32_t setLayerTransformHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
+ auto transform = static_cast<HWC2::Transform>(intTransform);
+ return callLayerFunction(device, display, layer, &Layer::setTransform,
+ transform);
+ }
+
+ static int32_t setLayerZOrderHook(hwc2_device_t* device,
+ hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
+ return callDisplayFunction(device, display, &Display::updateLayerZ,
+ layer, z);
+ }
+
+ // Adapter internals
+
+ void populateCapabilities();
+ Display* getDisplay(hwc2_display_t id);
+ std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
+ hwc2_layer_t layerId);
+ void populatePrimary();
+
+ bool prepareAllDisplays();
+ std::vector<struct hwc_display_contents_1*> mHwc1Contents;
+ HWC2::Error setAllDisplays();
+
+ // Callbacks
+ void hwc1Invalidate();
+ void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
+ void hwc1Hotplug(int hwc1DisplayId, int connected);
+
+ // These are set in the constructor and before any asynchronous events are
+ // possible
+
+ struct hwc_composer_device_1* const mHwc1Device;
+ const uint8_t mHwc1MinorVersion;
+ bool mHwc1SupportsVirtualDisplays;
+ bool mHwc1SupportsBackgroundColor;
+
+ class Callbacks;
+ const std::unique_ptr<Callbacks> mHwc1Callbacks;
+
+ std::unordered_set<HWC2::Capability> mCapabilities;
+
+ // These are only accessed from the main SurfaceFlinger thread (not from
+ // callbacks or dump
+
+ std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
+
+ // A HWC1 supports only one virtual display.
+ std::shared_ptr<Display> mHwc1VirtualDisplay;
+
+ // These are potentially accessed from multiple threads, and are protected
+ // by this mutex. This needs to be recursive, since the HWC1 implementation
+ // can call back into the invalidate callback on the same thread that is
+ // calling prepare.
+ std::recursive_timed_mutex mStateMutex;
+
+ struct CallbackInfo {
+ hwc2_callback_data_t data;
+ hwc2_function_pointer_t pointer;
+ };
+ std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
+ bool mHasPendingInvalidate;
+
+ // There is a small gap between the time the HWC1 module is started and
+ // when the callbacks for vsync and hotplugs are registered by the
+ // HWC2on1Adapter. To prevent losing events they are stored in these arrays
+ // and fed to the callback as soon as possible.
+ std::vector<std::pair<int, int64_t>> mPendingVsyncs;
+ std::vector<std::pair<int, int>> mPendingHotplugs;
+
+ // Mapping between HWC1 display id and Display objects.
+ std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+
+ // Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
+ // HWC_DISPLAY_VIRTUAL) to Display IDs generated by HWC2on1Adapter objects.
+ std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
+};
+
+} // namespace android
+
+#endif
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h b/graphics/composer/2.1/utils/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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 MINIFENCE_H
+#define MINIFENCE_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/* MiniFence is a minimal re-implementation of Fence from libui. It exists to
+ * avoid linking the HWC2on1Adapter to libui and satisfy Treble requirements.
+ */
+class MiniFence : public LightRefBase<MiniFence> {
+public:
+ static const sp<MiniFence> NO_FENCE;
+
+ // Construct a new MiniFence object with an invalid file descriptor.
+ MiniFence();
+
+ // Construct a new MiniFence object to manage a given fence file descriptor.
+ // When the new MiniFence object is destructed the file descriptor will be
+ // closed.
+ explicit MiniFence(int fenceFd);
+
+ // Not copyable or movable.
+ MiniFence(const MiniFence& rhs) = delete;
+ MiniFence& operator=(const MiniFence& rhs) = delete;
+ MiniFence(MiniFence&& rhs) = delete;
+ MiniFence& operator=(MiniFence&& rhs) = delete;
+
+ // Return a duplicate of the fence file descriptor. The caller is
+ // responsible for closing the returned file descriptor. On error, -1 will
+ // be returned and errno will indicate the problem.
+ int dup() const;
+
+private:
+ // Only allow instantiation using ref counting.
+ friend class LightRefBase<MiniFence>;
+ ~MiniFence();
+
+ int mFenceFd;
+
+};
+}
+#endif //MINIFENCE_H
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2010 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_shared {
+ name: "libhwc2onfbadapter",
+ vendor: true,
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ srcs: [
+ "HWC2OnFbAdapter.cpp",
+ ],
+
+ header_libs: ["libhardware_headers"],
+ shared_libs: ["liblog", "libsync"],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp b/graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
--- /dev/null
@@ -0,0 +1,887 @@
+/*
+ * Copyright 2017 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 "HWC2OnFbAdapter"
+
+//#define LOG_NDEBUG 0
+
+#include "hwc2onfbadapter/HWC2OnFbAdapter.h"
+
+#include <algorithm>
+#include <type_traits>
+
+#include <inttypes.h>
+#include <time.h>
+#include <sys/prctl.h>
+#include <unistd.h> // for close
+
+#include <hardware/fb.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+namespace android {
+
+namespace {
+
+void dumpHook(hwc2_device_t* device, uint32_t* outSize, char* outBuffer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (outBuffer) {
+ *outSize = adapter.getDebugString().copy(outBuffer, *outSize);
+ } else {
+ adapter.updateDebugString();
+ *outSize = adapter.getDebugString().size();
+ }
+}
+
+int32_t registerCallbackHook(hwc2_device_t* device, int32_t descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ switch (descriptor) {
+ case HWC2_CALLBACK_HOTPLUG:
+ if (pointer) {
+ reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer)(callbackData, adapter.getDisplayId(),
+ HWC2_CONNECTION_CONNECTED);
+ }
+ break;
+ case HWC2_CALLBACK_REFRESH:
+ break;
+ case HWC2_CALLBACK_VSYNC:
+ adapter.setVsyncCallback(reinterpret_cast<HWC2_PFN_VSYNC>(pointer), callbackData);
+ break;
+ default:
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* /*device*/) {
+ return 0;
+}
+
+int32_t createVirtualDisplayHook(hwc2_device_t* /*device*/, uint32_t /*width*/, uint32_t /*height*/,
+ int32_t* /*format*/, hwc2_display_t* /*outDisplay*/) {
+ return HWC2_ERROR_NO_RESOURCES;
+}
+
+int32_t destroyVirtualDisplayHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/) {
+ return HWC2_ERROR_BAD_DISPLAY;
+}
+
+int32_t setOutputBufferHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/,
+ buffer_handle_t /*buffer*/, int32_t /*releaseFence*/) {
+ return HWC2_ERROR_BAD_DISPLAY;
+}
+
+int32_t getDisplayNameHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outSize,
+ char* outName) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ const auto& info = adapter.getInfo();
+ if (outName) {
+ *outSize = info.name.copy(outName, *outSize);
+ } else {
+ *outSize = info.name.size();
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayTypeHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outType) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outType = HWC2_DISPLAY_TYPE_PHYSICAL;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDozeSupportHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outSupport) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outSupport = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getHdrCapabilitiesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes,
+ int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outNumTypes = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setPowerModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t /*mode*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // pretend that it works
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setVsyncEnabledHook(hwc2_device_t* device, hwc2_display_t display, int32_t enabled) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ adapter.enableVsync(enabled == HWC2_VSYNC_ENABLE);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getColorModesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumModes,
+ int32_t* outModes) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (outModes) {
+ if (*outNumModes > 0) {
+ outModes[0] = HAL_COLOR_MODE_NATIVE;
+ *outNumModes = 1;
+ }
+ } else {
+ *outNumModes = 1;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setColorModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t mode) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (mode != HAL_COLOR_MODE_NATIVE) {
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setColorTransformHook(hwc2_device_t* device, hwc2_display_t display,
+ const float* /*matrix*/, int32_t /*hint*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // we always force client composition
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getClientTargetSupportHook(hwc2_device_t* device, hwc2_display_t display, uint32_t width,
+ uint32_t height, int32_t format, int32_t dataspace) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (dataspace != HAL_DATASPACE_UNKNOWN) {
+ return HWC2_ERROR_UNSUPPORTED;
+ }
+
+ const auto& info = adapter.getInfo();
+ return (info.width == width && info.height == height && info.format == format)
+ ? HWC2_ERROR_NONE
+ : HWC2_ERROR_UNSUPPORTED;
+}
+
+int32_t setClientTargetHook(hwc2_device_t* device, hwc2_display_t display, buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace, hwc_region_t /*damage*/) {
+ if (acquireFence >= 0) {
+ sync_wait(acquireFence, -1);
+ close(acquireFence);
+ }
+
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (dataspace != HAL_DATASPACE_UNKNOWN) {
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ // no state change
+ adapter.setBuffer(target);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayConfigsHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumConfigs, hwc2_config_t* outConfigs) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (outConfigs) {
+ if (*outNumConfigs > 0) {
+ outConfigs[0] = adapter.getConfigId();
+ *outNumConfigs = 1;
+ }
+ } else {
+ *outNumConfigs = 1;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayAttributeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config,
+ int32_t attribute, int32_t* outValue) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getConfigId() != config) {
+ return HWC2_ERROR_BAD_CONFIG;
+ }
+
+ const auto& info = adapter.getInfo();
+ switch (attribute) {
+ case HWC2_ATTRIBUTE_WIDTH:
+ *outValue = int32_t(info.width);
+ break;
+ case HWC2_ATTRIBUTE_HEIGHT:
+ *outValue = int32_t(info.height);
+ break;
+ case HWC2_ATTRIBUTE_VSYNC_PERIOD:
+ *outValue = int32_t(info.vsync_period_ns);
+ break;
+ case HWC2_ATTRIBUTE_DPI_X:
+ *outValue = int32_t(info.xdpi_scaled);
+ break;
+ case HWC2_ATTRIBUTE_DPI_Y:
+ *outValue = int32_t(info.ydpi_scaled);
+ break;
+ default:
+ return HWC2_ERROR_BAD_PARAMETER;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getActiveConfigHook(hwc2_device_t* device, hwc2_display_t display,
+ hwc2_config_t* outConfig) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outConfig = adapter.getConfigId();
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setActiveConfigHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getConfigId() != config) {
+ return HWC2_ERROR_BAD_CONFIG;
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t validateDisplayHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ const auto& dirtyLayers = adapter.getDirtyLayers();
+ *outNumTypes = dirtyLayers.size();
+ *outNumRequests = 0;
+
+ if (*outNumTypes > 0) {
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED_WITH_CHANGES);
+ return HWC2_ERROR_HAS_CHANGES;
+ } else {
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED);
+ return HWC2_ERROR_NONE;
+ }
+}
+
+int32_t getChangedCompositionTypesHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outTypes) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ // request client composition for all layers
+ const auto& dirtyLayers = adapter.getDirtyLayers();
+ if (outLayers && outTypes) {
+ *outNumElements = std::min(*outNumElements, uint32_t(dirtyLayers.size()));
+ auto iter = dirtyLayers.cbegin();
+ for (uint32_t i = 0; i < *outNumElements; i++) {
+ outLayers[i] = *iter++;
+ outTypes[i] = HWC2_COMPOSITION_CLIENT;
+ }
+ } else {
+ *outNumElements = dirtyLayers.size();
+ }
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getDisplayRequestsHook(hwc2_device_t* device, hwc2_display_t display,
+ int32_t* outDisplayRequests, uint32_t* outNumElements,
+ hwc2_layer_t* /*outLayers*/, int32_t* /*outLayerRequests*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ *outDisplayRequests = 0;
+ *outNumElements = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t acceptDisplayChangesHook(hwc2_device_t* device, hwc2_display_t display) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ adapter.clearDirtyLayers();
+ adapter.setState(HWC2OnFbAdapter::State::VALIDATED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t presentDisplayHook(hwc2_device_t* device, hwc2_display_t display,
+ int32_t* outPresentFence) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (adapter.getState() != HWC2OnFbAdapter::State::VALIDATED) {
+ return HWC2_ERROR_NOT_VALIDATED;
+ }
+
+ adapter.postBuffer();
+ *outPresentFence = -1;
+
+ return HWC2_ERROR_NONE;
+}
+
+int32_t getReleaseFencesHook(hwc2_device_t* device, hwc2_display_t display,
+ uint32_t* outNumElements, hwc2_layer_t* /*outLayers*/,
+ int32_t* /*outFences*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outNumElements = 0;
+ return HWC2_ERROR_NONE;
+}
+
+int32_t createLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t* outLayer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ *outLayer = adapter.addLayer();
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+int32_t destroyLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ if (adapter.removeLayer(layer)) {
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+ } else {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+}
+
+int32_t setCursorPositionHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t /*layer*/,
+ int32_t /*x*/, int32_t /*y*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+
+ // always an error
+ return HWC2_ERROR_BAD_LAYER;
+}
+
+int32_t setLayerBufferHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ buffer_handle_t /*buffer*/, int32_t acquireFence) {
+ if (acquireFence >= 0) {
+ sync_wait(acquireFence, -1);
+ close(acquireFence);
+ }
+
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ // no state change
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setLayerSurfaceDamageHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ hwc_region_t /*damage*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ // no state change
+ return HWC2_ERROR_NONE;
+}
+
+int32_t setLayerCompositionTypeHook(hwc2_device_t* device, hwc2_display_t display,
+ hwc2_layer_t layer, int32_t type) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.markLayerDirty(layer, type != HWC2_COMPOSITION_CLIENT)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+template <typename... Args>
+int32_t setLayerStateHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer,
+ Args... /*args*/) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ if (adapter.getDisplayId() != display) {
+ return HWC2_ERROR_BAD_DISPLAY;
+ }
+ if (!adapter.hasLayer(layer)) {
+ return HWC2_ERROR_BAD_LAYER;
+ }
+
+ adapter.setState(HWC2OnFbAdapter::State::MODIFIED);
+ return HWC2_ERROR_NONE;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t asFP(T function) {
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+hwc2_function_pointer_t getFunctionHook(hwc2_device_t* /*device*/, int32_t descriptor) {
+ switch (descriptor) {
+ // global functions
+ case HWC2_FUNCTION_DUMP:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case HWC2_FUNCTION_REGISTER_CALLBACK:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // virtual display functions
+ case HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(getMaxVirtualDisplayCountHook);
+ case HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(createVirtualDisplayHook);
+ case HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(destroyVirtualDisplayHook);
+ case HWC2_FUNCTION_SET_OUTPUT_BUFFER:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(setOutputBufferHook);
+
+ // display functions
+ case HWC2_FUNCTION_GET_DISPLAY_NAME:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(getDisplayNameHook);
+ case HWC2_FUNCTION_GET_DISPLAY_TYPE:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(getDisplayTypeHook);
+ case HWC2_FUNCTION_GET_DOZE_SUPPORT:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(getDozeSupportHook);
+ case HWC2_FUNCTION_GET_HDR_CAPABILITIES:
+ return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(getHdrCapabilitiesHook);
+ case HWC2_FUNCTION_SET_POWER_MODE:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
+ case HWC2_FUNCTION_SET_VSYNC_ENABLED:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
+ case HWC2_FUNCTION_GET_COLOR_MODES:
+ return asFP<HWC2_PFN_GET_COLOR_MODES>(getColorModesHook);
+ case HWC2_FUNCTION_SET_COLOR_MODE:
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
+ case HWC2_FUNCTION_SET_COLOR_TRANSFORM:
+ return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
+ case HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT:
+ return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(getClientTargetSupportHook);
+ case HWC2_FUNCTION_SET_CLIENT_TARGET:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(setClientTargetHook);
+
+ // config functions
+ case HWC2_FUNCTION_GET_DISPLAY_CONFIGS:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(getDisplayConfigsHook);
+ case HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(getDisplayAttributeHook);
+ case HWC2_FUNCTION_GET_ACTIVE_CONFIG:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(getActiveConfigHook);
+ case HWC2_FUNCTION_SET_ACTIVE_CONFIG:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(setActiveConfigHook);
+
+ // validate/present functions
+ case HWC2_FUNCTION_VALIDATE_DISPLAY:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(validateDisplayHook);
+ case HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(getChangedCompositionTypesHook);
+ case HWC2_FUNCTION_GET_DISPLAY_REQUESTS:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(getDisplayRequestsHook);
+ case HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(acceptDisplayChangesHook);
+ case HWC2_FUNCTION_PRESENT_DISPLAY:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(presentDisplayHook);
+ case HWC2_FUNCTION_GET_RELEASE_FENCES:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(getReleaseFencesHook);
+
+ // layer create/destroy
+ case HWC2_FUNCTION_CREATE_LAYER:
+ return asFP<HWC2_PFN_CREATE_LAYER>(createLayerHook);
+ case HWC2_FUNCTION_DESTROY_LAYER:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(destroyLayerHook);
+
+ // layer functions; validateDisplay not required
+ case HWC2_FUNCTION_SET_CURSOR_POSITION:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(setCursorPositionHook);
+ case HWC2_FUNCTION_SET_LAYER_BUFFER:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(setLayerBufferHook);
+ case HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(setLayerSurfaceDamageHook);
+
+ // layer state functions; validateDisplay required
+ case HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(setLayerCompositionTypeHook);
+ case HWC2_FUNCTION_SET_LAYER_BLEND_MODE:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_COLOR:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(setLayerStateHook<hwc_color_t>);
+ case HWC2_FUNCTION_SET_LAYER_DATASPACE:
+ return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(setLayerStateHook<hwc_rect_t>);
+ case HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(setLayerStateHook<float>);
+ case HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(setLayerStateHook<buffer_handle_t>);
+ case HWC2_FUNCTION_SET_LAYER_SOURCE_CROP:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(setLayerStateHook<hwc_frect_t>);
+ case HWC2_FUNCTION_SET_LAYER_TRANSFORM:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerStateHook<int32_t>);
+ case HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(setLayerStateHook<hwc_region_t>);
+ case HWC2_FUNCTION_SET_LAYER_Z_ORDER:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerStateHook<uint32_t>);
+
+ default:
+ ALOGE("unknown function descriptor %d", descriptor);
+ return nullptr;
+ }
+}
+
+void getCapabilitiesHook(hwc2_device_t* /*device*/, uint32_t* outCount,
+ int32_t* /*outCapabilities*/) {
+ *outCount = 0;
+}
+
+int closeHook(hw_device_t* device) {
+ auto& adapter = HWC2OnFbAdapter::cast(device);
+ adapter.close();
+ return 0;
+}
+
+} // anonymous namespace
+
+HWC2OnFbAdapter::HWC2OnFbAdapter(framebuffer_device_t* fbDevice)
+ : hwc2_device_t(), mFbDevice(fbDevice) {
+ common.close = closeHook;
+ hwc2_device::getCapabilities = getCapabilitiesHook;
+ hwc2_device::getFunction = getFunctionHook;
+
+ mFbInfo.name = "fbdev";
+ mFbInfo.width = mFbDevice->width;
+ mFbInfo.height = mFbDevice->height;
+ mFbInfo.format = mFbDevice->format;
+ mFbInfo.vsync_period_ns = int(1e9 / mFbDevice->fps);
+ mFbInfo.xdpi_scaled = int(mFbDevice->xdpi * 1000.0f);
+ mFbInfo.ydpi_scaled = int(mFbDevice->ydpi * 1000.0f);
+
+ mVsyncThread.start(0, mFbInfo.vsync_period_ns);
+}
+
+HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hw_device_t* device) {
+ return *reinterpret_cast<HWC2OnFbAdapter*>(device);
+}
+
+HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hwc2_device_t* device) {
+ return *reinterpret_cast<HWC2OnFbAdapter*>(device);
+}
+
+hwc2_display_t HWC2OnFbAdapter::getDisplayId() {
+ return 0;
+}
+
+hwc2_config_t HWC2OnFbAdapter::getConfigId() {
+ return 0;
+}
+
+void HWC2OnFbAdapter::close() {
+ mVsyncThread.stop();
+ framebuffer_close(mFbDevice);
+}
+
+const HWC2OnFbAdapter::Info& HWC2OnFbAdapter::getInfo() const {
+ return mFbInfo;
+}
+
+void HWC2OnFbAdapter::updateDebugString() {
+ if (mFbDevice->common.version >= 1 && mFbDevice->dump) {
+ char buffer[4096];
+ mFbDevice->dump(mFbDevice, buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ mDebugString = buffer;
+ }
+}
+
+const std::string& HWC2OnFbAdapter::getDebugString() const {
+ return mDebugString;
+}
+
+void HWC2OnFbAdapter::setState(State state) {
+ mState = state;
+}
+
+HWC2OnFbAdapter::State HWC2OnFbAdapter::getState() const {
+ return mState;
+}
+
+hwc2_layer_t HWC2OnFbAdapter::addLayer() {
+ hwc2_layer_t id = ++mNextLayerId;
+
+ mLayers.insert(id);
+ mDirtyLayers.insert(id);
+
+ return id;
+}
+
+bool HWC2OnFbAdapter::removeLayer(hwc2_layer_t layer) {
+ mDirtyLayers.erase(layer);
+ return mLayers.erase(layer);
+}
+
+bool HWC2OnFbAdapter::hasLayer(hwc2_layer_t layer) const {
+ return mLayers.count(layer) > 0;
+}
+
+bool HWC2OnFbAdapter::markLayerDirty(hwc2_layer_t layer, bool dirty) {
+ if (mLayers.count(layer) == 0) {
+ return false;
+ }
+
+ if (dirty) {
+ mDirtyLayers.insert(layer);
+ } else {
+ mDirtyLayers.erase(layer);
+ }
+
+ return true;
+}
+
+const std::unordered_set<hwc2_layer_t>& HWC2OnFbAdapter::getDirtyLayers() const {
+ return mDirtyLayers;
+}
+
+void HWC2OnFbAdapter::clearDirtyLayers() {
+ mDirtyLayers.clear();
+}
+
+/*
+ * For each frame, SurfaceFlinger
+ *
+ * - peforms GLES composition
+ * - calls eglSwapBuffers
+ * - calls setClientTarget, which maps to setBuffer below
+ * - calls presentDisplay, which maps to postBuffer below
+ *
+ * setBuffer should be a good place to call compositionComplete.
+ *
+ * As for post, it
+ *
+ * - schedules the buffer for presentation on the next vsync
+ * - locks the buffer and blocks all other users trying to lock it
+ *
+ * It does not give us a way to return a present fence, and we need to live
+ * with that. The implication is that, when we are double-buffered,
+ * SurfaceFlinger assumes the front buffer is available for rendering again
+ * immediately after the back buffer is posted. The locking semantics
+ * hopefully are strong enough that the rendering will be blocked.
+ */
+void HWC2OnFbAdapter::setBuffer(buffer_handle_t buffer) {
+ if (mFbDevice->compositionComplete) {
+ mFbDevice->compositionComplete(mFbDevice);
+ }
+ mBuffer = buffer;
+}
+
+bool HWC2OnFbAdapter::postBuffer() {
+ int error = 0;
+ if (mBuffer) {
+ error = mFbDevice->post(mFbDevice, mBuffer);
+ }
+
+ return error == 0;
+}
+
+void HWC2OnFbAdapter::setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) {
+ mVsyncThread.setCallback(callback, data);
+}
+
+void HWC2OnFbAdapter::enableVsync(bool enable) {
+ mVsyncThread.enableCallback(enable);
+}
+
+int64_t HWC2OnFbAdapter::VsyncThread::now() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return int64_t(ts.tv_sec) * 1'000'000'000 + ts.tv_nsec;
+}
+
+bool HWC2OnFbAdapter::VsyncThread::sleepUntil(int64_t t) {
+ struct timespec ts;
+ ts.tv_sec = t / 1'000'000'000;
+ ts.tv_nsec = t % 1'000'000'000;
+
+ while (true) {
+ int error = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr);
+ if (error) {
+ if (error == EINTR) {
+ continue;
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
+
+void HWC2OnFbAdapter::VsyncThread::start(int64_t firstVsync, int64_t period) {
+ mNextVsync = firstVsync;
+ mPeriod = period;
+ mStarted = true;
+ mThread = std::thread(&VsyncThread::vsyncLoop, this);
+}
+
+void HWC2OnFbAdapter::VsyncThread::stop() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStarted = false;
+ }
+ mCondition.notify_all();
+ mThread.join();
+}
+
+void HWC2OnFbAdapter::VsyncThread::setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallback = callback;
+ mCallbackData = data;
+}
+
+void HWC2OnFbAdapter::VsyncThread::enableCallback(bool enable) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCallbackEnabled = enable;
+ }
+ mCondition.notify_all();
+}
+
+void HWC2OnFbAdapter::VsyncThread::vsyncLoop() {
+ prctl(PR_SET_NAME, "VsyncThread", 0, 0, 0);
+
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (!mStarted) {
+ return;
+ }
+
+ while (true) {
+ if (!mCallbackEnabled) {
+ mCondition.wait(lock, [this] { return mCallbackEnabled || !mStarted; });
+ if (!mStarted) {
+ break;
+ }
+ }
+
+ lock.unlock();
+
+ // adjust mNextVsync if necessary
+ int64_t t = now();
+ if (mNextVsync < t) {
+ int64_t n = (t - mNextVsync + mPeriod - 1) / mPeriod;
+ mNextVsync += mPeriod * n;
+ }
+ bool fire = sleepUntil(mNextVsync);
+
+ lock.lock();
+
+ if (fire) {
+ ALOGV("VsyncThread(%" PRId64 ")", mNextVsync);
+ if (mCallback) {
+ mCallback(mCallbackData, getDisplayId(), mNextVsync);
+ }
+ mNextVsync += mPeriod;
+ }
+ }
+}
+
+} // namespace android
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h b/graphics/composer/2.1/utils/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017 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_SF_HWC2_ON_FB_ADAPTER_H
+#define ANDROID_SF_HWC2_ON_FB_ADAPTER_H
+
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <unordered_set>
+
+#include <hardware/hwcomposer2.h>
+
+struct framebuffer_device_t;
+
+namespace android {
+
+class HWC2OnFbAdapter : public hwc2_device_t {
+public:
+ HWC2OnFbAdapter(framebuffer_device_t* fbDevice);
+
+ static HWC2OnFbAdapter& cast(hw_device_t* device);
+ static HWC2OnFbAdapter& cast(hwc2_device_t* device);
+
+ static hwc2_display_t getDisplayId();
+ static hwc2_config_t getConfigId();
+
+ void close();
+
+ struct Info {
+ std::string name;
+ uint32_t width;
+ uint32_t height;
+ int format;
+ int vsync_period_ns;
+ int xdpi_scaled;
+ int ydpi_scaled;
+ };
+ const Info& getInfo() const;
+
+ void updateDebugString();
+ const std::string& getDebugString() const;
+
+ enum class State {
+ MODIFIED,
+ VALIDATED_WITH_CHANGES,
+ VALIDATED,
+ };
+ void setState(State state);
+ State getState() const;
+
+ hwc2_layer_t addLayer();
+ bool removeLayer(hwc2_layer_t layer);
+ bool hasLayer(hwc2_layer_t layer) const;
+ bool markLayerDirty(hwc2_layer_t layer, bool dirty);
+ const std::unordered_set<hwc2_layer_t>& getDirtyLayers() const;
+ void clearDirtyLayers();
+
+ void setBuffer(buffer_handle_t buffer);
+ bool postBuffer();
+
+ void setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
+ void enableVsync(bool enable);
+
+private:
+ framebuffer_device_t* mFbDevice{nullptr};
+ Info mFbInfo{};
+
+ std::string mDebugString;
+
+ State mState{State::MODIFIED};
+
+ uint64_t mNextLayerId{0};
+ std::unordered_set<hwc2_layer_t> mLayers;
+ std::unordered_set<hwc2_layer_t> mDirtyLayers;
+
+ buffer_handle_t mBuffer{nullptr};
+
+ class VsyncThread {
+ public:
+ static int64_t now();
+ static bool sleepUntil(int64_t t);
+
+ void start(int64_t first, int64_t period);
+ void stop();
+ void setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data);
+ void enableCallback(bool enable);
+
+ private:
+ void vsyncLoop();
+ bool waitUntilNextVsync();
+
+ std::thread mThread;
+ int64_t mNextVsync{0};
+ int64_t mPeriod{0};
+
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mStarted{false};
+ HWC2_PFN_VSYNC mCallback{nullptr};
+ hwc2_callback_data_t mCallbackData{nullptr};
+ bool mCallbackEnabled{false};
+ };
+ VsyncThread mVsyncThread;
+};
+
+} // namespace android
+
+#endif // ANDROID_SF_HWC2_ON_FB_ADAPTER_H
index 4ee206bcdcd5e654605e1609417e9da0189f9f17..45661357af2586e0793c68b37e6c24c22e299605 100644 (file)
* @param cpuUsage specifies one or more CPU usage flags to request.
* @param accessRegion is the portion of the buffer that the client
* intends to access.
- * @param acquireFence, when non-empty, is a handle containing a file
+ * @param acquireFence when non-empty, is a handle containing a file
* descriptor referring to a sync fence object, which will be
* signaled when it is safe for the mapper to lock the buffer. If
* it is already safe to lock, acquireFence is empty.
* @param cpuUsage specifies one or more CPU usage flags to request.
* @param accessRegion is the portion of the buffer that the client
* intends to access.
- * @param acquireFence, when non-empty, is a handle containing a file
+ * @param acquireFence when non-empty, is a handle containing a file
* descriptor referring to a sync fence object, which will be
* signaled when it is safe for the mapper to lock the buffer. If
* it is already safe to lock, acquireFence is empty.
index e9b2f3a76cbb93da1da4bfe1189783868376393f..2291f70085c45d7099a90a11670e04c62fc50bb1 100644 (file)
package android.hardware.graphics.mapper@2.0;
enum Error : int32_t {
- NONE = 0, /** no error */
- BAD_DESCRIPTOR = 1, /** invalid BufferDescriptor */
- BAD_BUFFER = 2, /** invalid buffer handle */
- BAD_VALUE = 3, /** invalid width, height, etc. */
+ NONE = 0, /* no error */
+ BAD_DESCRIPTOR = 1, /* invalid BufferDescriptor */
+ BAD_BUFFER = 2, /* invalid buffer handle */
+ BAD_VALUE = 3, /* invalid width, height, etc. */
/* 4 is reserved */
- NO_RESOURCES = 5, /** temporary failure due to resource contention */
+ NO_RESOURCES = 5, /* temporary failure due to resource contention */
/* 6 is reserved */
- UNSUPPORTED = 7, /** permanent failure */
+ UNSUPPORTED = 7, /* permanent failure */
};
/**
diff --git a/health/2.0/README b/health/2.0/README
index 49b2b1ebc6dd2304b48228e671809942479ccd05..7381cc379a1d9721add52b005d0853a6f88a801b 100644 (file)
--- a/health/2.0/README
+++ b/health/2.0/README
Upgrading from health@1.0 HAL
-0. Remove android.hardware.health@1.0* from PRDOUCT_PACKAGES
+0. Remove android.hardware.health@1.0* from PRODUCT_PACKAGES
in device/<manufacturer>/<device>/device.mk
1. If the device does not have a vendor-specific libhealthd AND does not
index 6dad23e4d30f788efe9ce050f0aa28e7c73febda..72f7d47347cb240c8b974ffd76ffb6139d15a0e6 100644 (file)
--- a/keymaster/3.0/types.hal
+++ b/keymaster/3.0/types.hal
package android.hardware.keymaster@3.0;
enum TagType : uint32_t {
- INVALID = 0 << 28, /** Invalid type, used to designate a tag as uninitialized */
+ INVALID = 0 << 28, /* Invalid type, used to designate a tag as uninitialized */
ENUM = 1 << 28,
- ENUM_REP = 2 << 28, /** Repeatable enumeration value. */
+ ENUM_REP = 2 << 28, /* Repeatable enumeration value. */
UINT = 3 << 28,
- UINT_REP = 4 << 28, /** Repeatable integer value */
+ UINT_REP = 4 << 28, /* Repeatable integer value */
ULONG = 5 << 28,
DATE = 6 << 28,
BOOL = 7 << 28,
BIGNUM = 8 << 28,
BYTES = 9 << 28,
- ULONG_REP = 10 << 28, /** Repeatable long value */
+ ULONG_REP = 10 << 28, /* Repeatable long value */
};
enum Tag : uint32_t {
* Possible purposes of a key (or pair).
*/
enum KeyPurpose : uint32_t {
- ENCRYPT = 0, /** Usable with RSA, EC and AES keys. */
- DECRYPT = 1, /** Usable with RSA, EC and AES keys. */
- SIGN = 2, /** Usable with RSA, EC and HMAC keys. */
- VERIFY = 3, /** Usable with RSA, EC and HMAC keys. */
- DERIVE_KEY = 4, /** Usable with EC keys. */
- WRAP_KEY = 5, /** Usable with wrapping keys. */
+ ENCRYPT = 0, /* Usable with RSA, EC and AES keys. */
+ DECRYPT = 1, /* Usable with RSA, EC and AES keys. */
+ SIGN = 2, /* Usable with RSA, EC and HMAC keys. */
+ VERIFY = 3, /* Usable with RSA, EC and HMAC keys. */
+ DERIVE_KEY = 4, /* Usable with EC keys. */
+ WRAP_KEY = 5, /* Usable with wrapping keys. */
};
/**
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index d5c006ea8fbb64e4929a6b3c6a3646f04eee7ec3..c90e96cda12145de929d6d11594d8c4d61317251 100644 (file)
}
bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) {
- for (size_t i = 0; i < chain.size() - 1; ++i) {
+ for (size_t i = 0; i < chain.size(); ++i) {
X509_Ptr key_cert(parse_cert_blob(chain[i]));
X509_Ptr signing_cert;
if (i < chain.size() - 1) {
index 49c29674eed2ad35e11c063178253f6823f29095..62fb2baed56e5252b37566ee9f5dcbf8d8839285 100644 (file)
/**
* Gets the supported operations in a model.
*
- * getSupportedSubgraph indicates which operations of a model are fully
+ * getSupportedOperations indicates which operations of a model are fully
* supported by the vendor driver. If an operation may not be supported for
* any reason, getSupportedOperations must return false for that operation.
*
index ef0f4549dd09d53da876257e14a98416d5b29cc5..9c0616696d451e68524c8282b53ddaf63647e2b1 100644 (file)
* ErrorStatus resulting from the execution. If the asynchronous task
* is not launched, notify must be invoked with the appropriate error.
*
- * @return param Error status returned from launching the asynchronous task
+ * @param status Error status returned from launching the asynchronous task
* (if the launch fails) or from the asynchronous task itself
* (if the launch succeeds). Must be:
* - NONE if the asynchronous execution was successful
index 8779723d2fd07f2ba9eee1b8d1834bb5fb11eb9f..4efa13add0a1f69828b8df6bcedd25a571419608 100644 (file)
* 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.
+ *
+ * Although many types are defined, most operators accept just a few
+ * types. Most used are {@link OperandType::TENSOR_FLOAT32},
+ * {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * and {@link OperandType::INT32}.
*/
enum OperandType : int32_t {
- /**
- * The following entries are used to declare scalars.
- */
+ /** 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,
- /**
- * The following entries are used to declare tensors.
- */
+ /** 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 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
- * - zero_value: a 32 bit integer
+ * - 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 - zero_value) * scale.
+ * real_value = (integer_value - zeroPoint) * scale.
*/
TENSOR_QUANT8_ASYMM = 5,
- /**
- * The following entries are OEM specific operand types.
- */
+ /** OEM specific scalar value. */
OEM = 10000,
+
+ /** A tensor of OEM specific values. */
TENSOR_OEM_BYTE = 10001,
};
*/
enum OperationType : int32_t {
/**
- * Adds two tensors, elment-wise.
+ * Adds two tensors, element-wise.
*
- * Takes two input tensors of identical type and compatible dimensions. The output
- * is the sum of both input tensors, optionally modified by an activation function.
+ * Takes two input tensors of identical {@link OperandType} and compatible
+ * dimensions. The output is the sum of both input tensors, optionally
+ * modified by an activation function.
*
* Two dimensions are compatible when:
* 1. they are equal, or
* 2. one of them is 1
*
- * The size of the output is the maximum size along each dimension of the input operands.
- * It starts with the trailing dimensions, and works its way forward.
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its
+ * way forward.
*
* Example:
- * input1.dimension = {4, 1, 2}
+ *
+ * input1.dimension = {4, 1, 2}
* input2.dimension = {5, 4, 3, 1}
* output.dimension = {5, 4, 3, 2}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: A tensor.
- * 1: A tensor of the same type, and compatible dimensions as input0.
- * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
*
- * Ouputs:
- * 0: The sum, a tensor of the same type as input0.
+ * Outputs:
+ * * 0: The sum, a tensor of the same {@link OperandType} as input0.
*/
ADD = 0,
/**
* Performs a 2-D average pooling operation.
*
- * The output dimensions are functions of the filter dimensions, stride, and padding.
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
*
- * The values in output Tensor is computed as:
* output[batch, row, col, channel] =
* sum_{i, j}(input[batch, row + i, col + j, channel]) / sum(1)
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
- * Supported tensor rank: 4, with "NHWC" data layout.
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: 4, with "NHWC" (i.e., Num_samples, Height, Width,
+ * and Channels) data layout.
+ *
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+ * width.
+ * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+ * height.
+ * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+ * width.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+ * height.
+ * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
*
- * Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input.
- * 1: An INT32 value, specifying the padding on the left, in the ‘width’ dimension.
- * 2: An INT32 value, specifying the padding on the right,in the ‘width’ dimension.
- * 3: An INT32 value, specifying the padding on the top, in the ‘height’ dimension.
- * 4: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension.
- * 5: An INT32 value, specifying the output stride in the ‘width’ dimension.
- * 6: An INT32 value, specifying the output stride in the ‘height’ dimension.
- * 7: An INT32 value, specifying the filter width.
- * 8: An INT32 value, specifying the filter height.
- * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
- *
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth].
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ [batches, out_height, out_width, depth].
*/
AVERAGE_POOL_2D = 1,
/**
* Concatenates the input tensors along the given dimension.
*
- * The input tensors must have identical type and the same dimensions except the
- * dimension along the concatenation axis.
+ * The input tensors must have identical {@link OperandType} and the same
+ * dimensions except the dimension along the concatenation axis.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: up to 4
*
* Inputs:
- * 0 ~ n: The list on n input tensors, of shape [D0, D1, ..., Daxis(i), ..., Dm]
- * n+1: An INT32 value, specifying the concatenation axis.
- * n+2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
+ * * 0 ~ n-1: The list of n input tensors, of shape
+ * [D0, D1, ..., Daxis(i), ..., Dm]. For inputs of
+ * {@link OperandType::TENSOR_QUANT8_ASYMM}, all input tensors
+ * must have the same scale and zeroPoint.
+ * * n: An {@link OperandType::INT32} scalar, specifying the
+ * concatenation axis.
*
- * Ouputs:
- * 0: The output, a tensor of the same type as the input tensors.
- The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
+ * Outputs:
+ * * 0: The output, a tensor of the same {@link OperandType} as the input
+ * tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
*/
CONCATENATION = 2,
/**
* Performs an 2-D convolution operation.
*
- * The CONV_2D op sweeps a 2-D filter that can mix channels together over a batch of
- * images, applying the filter to each window of each image of the appropriate size.
+ * The CONV_2D op sweeps a 2-D filter that can mix channels together over a
+ * batch of images, applying the filter to each window of each image of the
+ * appropriate size.
+ *
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
*
- * The output dimensions are functions of the filter dimensions, stride, and padding.
+ * The values in the output tensor are computed as:
*
- * The values in output Tensor is computed as:
* output[batch, row, col, channel] =
* sum_{i, j} (
* input[batch, row + i, col + j, k] *
* bias[channel]
* )
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: 4, with "NHWC" data layout.
*
- * Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input.
- * 1: A 4-D tensor, of shape [depth_out, filter_height, filter_width, depth_in],
- * specifying the filter.
- * 2: A 1-D tensor, of shape [depth_out], specifying the bias.
- * For input tensor of {@link OperandType::TENSOR_FLOAT32} type, the bias should
- * also be of {@link OperandType::TENSOR_FLOAT32}.
- * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} type, the bias
- * should be of {@link OperandType::TENSOR_INT32}.
- * 3: An INT32 value, specifying the padding on the left, in the ‘width’ dimension.
- * 4: An INT32 value, specifying the padding on the right,in the ‘width’ dimension.
- * 5: An INT32 value, specifying the padding on the top, in the ‘height’ dimension.
- * 6: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension.
- * 7: An INT32 value, specifying the output stride in the ‘width’ dimension.
- * 8: An INT32 value, specifying the output stride in the ‘height’ dimension.
- * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
- *
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth_out].
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_in], specifying the
+ * filter.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias.
+ * For input tensor of {@link OperandType::TENSOR_FLOAT32}, the bias
+ * should also be of {@link OperandType::TENSOR_FLOAT32}. For input
+ * tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias
+ * should be of {@link OperandType::TENSOR_INT32}, with zeroPoint of
+ * 0 and bias_scale == input_scale * filter_scale.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: A 4-D tensor, of shape
+ * [depth_out, filter_height, filter_width, depth_in], specifying the
+ * filter.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
+ * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
+ * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+ * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+ * bias_scale == input_scale * filter_scale.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth_out]. For output tensor of
+ * {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
+ * must be satisfied: output_scale > input_scale * filter_scale.
*/
CONV_2D = 3,
/**
- * Performs an depthwise 2-D convolution operation.
+ * Performs a depthwise 2-D convolution operation.
*
- * Given an input tensor of shape [batches, height, width, depth_in] and a filter
- * tensor of shape [depth_out, filter_height, filter_width, depth_in] containing
- * in_channels convolutional filters of depth 1, DEPTHWISE_CONV applies a different
- * filter to each input channel (expanding from 1 channel to channel_multiplier channels
- * for each), then concatenates the results together.
+ * Given an input tensor of shape [batches, height, width, depth_in] and a
+ * filter tensor of shape [1, filter_height, filter_width, depth_out]
+ * containing depth_out convolutional filters of depth 1, DEPTHWISE_CONV
+ * applies a different filter to each input channel (expanding from 1
+ * channel to channel_multiplier channels for each), then concatenates the
+ * results together.
*
* The output has depth_out = depth_in * depth_multiplier channels.
- * The output dimensions are functions of the filter dimensions, stride, and padding.
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
*
- * The values in output Tensor is computed as:
* output[b, i, j, k * channel_multiplier + q] =
* sum_{di, dj} (
* input[b, strides[1] * i + di, strides[2] * j + dj, k] *
- * filter[di, dj, k, q]
+ * filter[1, di, dj, k * channel_multiplier + q]
* )
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: 4, with "NHWC" data layout.
*
- * Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input.
- * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
- * specifying the filter.
- * 2: A 1-D tensor, of shape [depth_out], specifying the bias.
- * For input tensor of {@link OperandType::TENSOR_FLOAT32} type, the bias should
- * also be of {@link OperandType::TENSOR_FLOAT32}.
- * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} type, the bias
- * should be of {@link OperandType::TENSOR_INT32}.
- * 3: An INT32 value, specifying the padding on the left, in the ‘width’ dimension.
- * 4: An INT32 value, specifying the padding on the right,in the ‘width’ dimension.
- * 5: An INT32 value, specifying the padding on the top, in the ‘height’ dimension.
- * 6: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension.
- * 7: An INT32 value, specifying the output stride in the ‘width’ dimension.
- * 8: An INT32 value, specifying the output stride in the ‘height’ dimension.
- * 9: An INT32 value, specifying the depthwise multiplier.
- * 10: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
- *
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth_out].
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+ * specifying the filter.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
+ * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
+ * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+ * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+ * bias_scale == input_scale * filter_scale.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 7: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 9: An {@link OperandType::INT32} scalar, specifying the depthwise
+ * multiplier.
+ * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: A 4-D tensor, of shape [1, filter_height, filter_width, depth_out],
+ * specifying the filter.
+ * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input
+ * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
+ * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
+ * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+ * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+ * bias_scale == input_scale * filter_scale.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, specifying the depthwise
+ * multiplier.
+ * * 7: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth_out]. For output tensor of
+ * {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition
+ * must be satisfied: output_scale > input_scale * filter_scale.
*/
DEPTHWISE_CONV_2D = 4,
/**
* Rearranges data from depth into blocks of spatial data.
*
- * More specifically, this op outputs a copy of the input tensor where values from
- * the depth dimension are moved in spatial blocks to the height and width dimensions.
- * The value block_size indicates the input block size and how the data is moved.
+ * More specifically, this op outputs a copy of the input tensor where
+ * values from the depth dimension are moved in spatial blocks to the height
+ * and width dimensions. The value block_size indicates the input block size
+ * and how the data is moved.
*
- * Chunks of data of size block_size * block_size from depth are rearranged into
- * non-overlapping blocks of size block_size x block_size.
+ * Chunks of data of size block_size * block_size from depth are rearranged
+ * into non-overlapping blocks of size block_size x block_size.
*
- * The width of the output tensor is input_depth * block_size, whereas the height is
- * input_height * block_size.
- * The depth of the input tensor must be divisible by block_size * block_size
+ * The width of the output tensor is input_depth * block_size, whereas the
+ * height is input_height * block_size. The depth of the input tensor must
+ * be divisible by block_size * block_size
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: 4, with "NHWC" data layout.
*
* Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input.
- * 1: An INT32 value, specifying the block_size. block_size must be >=1 and
- * block_size * block_size must be a divisor of the input depth.
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the block_size.
+ * block_size must be >=1 and block_size * block_size must be a divisor
+ * of the input depth.
*
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batch, height*block_size, width*block_size,
- * depth/(block_size*block_size)].
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape [batch, height*block_size,
+ * width*block_size, depth/(block_size*block_size)].
*/
DEPTH_TO_SPACE = 5,
* Dequantizes the input tensor.
*
* The formula is:
- * output = (input - zero_value) * scale.
*
- * Supported tensor types: {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * output = (input - zeroPoint) * scale.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: A tensor of type {@link OperandType::TENSOR_QUANT8_ASYMM}.
+ * * 0: A tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0, but with type
- {@link OperandType::TENSOR_FLOAT32}.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0, but with
+ * {@link OperandType::TENSOR_FLOAT32}.
*/
DEQUANTIZE = 6,
/**
- * Looks up items from a given tensor.
+ * Looks up sub-tensors in the input tensor.
*
- * Each item in the output is a raw copy of the corresponding item in
- * the input “values”. If the the given “lookup” indices are out of bounds,
- * the op will fail and an error will be reported.
+ * This operator takes for input a tensor of values (Values) and
+ * a one-dimensional tensor of selection indices (Lookups).
+ * The output tensor is the concatenation of sub-tensors of Values as
+ * selected by Lookups.
+ *
+ * Think of Values as being sliced along its first dimension:
+ * The entries in Lookups select which slices are concatenated together
+ * to create the output tensor.
+ *
+ * For example, if Values has shape of [40, 200, 300] and
+ * Lookups has shape of [3], all three values found in Lookups are
+ * expected to be between 0 and 39. The resulting tensor must
+ * have shape of [3, 200, 300].
+ *
+ * If a value in Lookups is out of bounds, the operation must fail
+ * and an error must be reported.
*
* Inputs:
- * * 0: Values. An n-D tensor of any type X (where n >= 2). E.g., if n is 2,
- * then the shape would be [lookup_dimension, values_dimension], where
- * “lookup_dimension” corresponds to the indexing dimension in the lookup
- * table, and “values_dimension” to the contents.
- * * 1: Lookups. An 1-D tensor of type T, of shape [lookup_size], where
- * “lookup_size” is the number of elements to look for, and each entry
- * corresponds to the first dimension of the “values” tensor.
+ * * 0: Lookups. A 1-D tensor of {@link OperandType::TENSOR_INT32}.
+ * The values are indices into the first dimension of Values.
+ * * 1: Values. An n-D tensor, where n >= 2, from which sub-tensors are
+ * extracted.
*
* Output:
- * * 0: A n-D tensor of type X and the same rank and shape as the “values”
- * tensor, except for the first dimension which has size “lookup_size”.
+ * * 0: A n-D tensor with the same rank and shape as the Values
+ * tensor, except for the first dimension which has the same size
+ * as Lookups' only dimension.
*/
EMBEDDING_LOOKUP = 7,
/**
* Computes element-wise floor() on the input tensor.
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: A tensor.
+ * * 0: A tensor.
*
- * Ouputs:
- * 0: The output, a tensor of the same type and dimensions as input0.
+ * Outputs:
+ * * 0: The output tensor, of the same {@link OperandType} and dimensions as
+ * the input tensor.
*/
FLOOR = 8,
/**
- * Denotes a fully (densely) connected layer, which connects all elements in the input
- * tensor with each element in the output tensor.
+ * Denotes a fully (densely) connected layer, which connects all elements
+ * in the input tensor with each element in the output tensor.
*
* This layer implements the operation:
+ *
* outputs = activation(inputs * weights’ + bias)
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the input. If rank is greater than 2, then it gets flattened to
- * a 2-D Tensor. The 2-D Tensor is handled as if dimensions corresponded to shape
- * [batch_size, input_size], where “batch_size” corresponds to the batching dimension,
- * and “input_size” is the size of the input.
- * 1: A 2-D tensor, specifying the weights, of shape [num_units, input_size], where “num_units”
- * corresponds to the number of output nodes.
- * 2: A 1-D tensor, of shape [num_units], specifying the bias.
- * For input tensor of {@link OperandType::TENSOR_FLOAT32} type, the bias should
- * also be of {@link OperandType::TENSOR_FLOAT32}.
- * For input tensor of {@link OperandType::TENSOR_QUANT8_ASYMM} type, the bias
- * should be of {@link OperandType::TENSOR_INT32}.
- * 3: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
- *
- * Ouputs:
- * 0: The output tensor, of shape [batch_size, num_units].
+ * * 0: A tensor of at least rank 2, specifying the input. If rank is
+ * greater than 2, then it gets flattened to a 2-D Tensor. The
+ * (flattened) 2-D Tensor is reshaped (if necessary) to
+ * [batch_size, input_size], where "input_size" corresponds to the
+ * number of inputs to the layer, matching the second dimension of
+ * weights, and "batch_size" is calculated by dividing the number of
+ * elements by "input_size".
+ * * 1: A 2-D tensor, specifying the weights, of shape
+ * [num_units, input_size], where "num_units" corresponds to the number
+ * of output nodes.
+ * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input
+ * tensor of {@link OperandType::TENSOR_FLOAT32}, the bias should
+ * also be of {@link OperandType::TENSOR_FLOAT32}. For input tensor
+ * of {@link OperandType::TENSOR_QUANT8_ASYMM}, the bias should be
+ * of {@link OperandType::TENSOR_INT32}, with zeroPoint of 0 and
+ * bias_scale == input_scale * filter_scale.
+ * * 3: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Outputs:
+ * * 0: The output tensor, of shape [batch_size, num_units]. For output
+ * tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
+ * condition must be satisfied:
+ * output_scale > input_scale * filter_scale.
*/
FULLY_CONNECTED = 9,
/**
- * Looks up values of a hash table with given keys.
+ * Looks up sub-tensors in the input tensor using a key-value map.
+ *
+ * This operator takes for input a tensor of values (Values),
+ * a one-dimensional tensor of selection values (Lookups) and
+ * a one-dimensional tensor that maps these values to Values
+ * indexes. The output tensor is the concatenation of sub-tensors of
+ * Values as selected by Lookups via Keys.
+ *
+ * Think of Values as being sliced along its outer-most dimension.
+ * The output is a concatenation of selected slices, with one slice
+ * for each entry of Lookups. The slice selected is the one at the
+ * same index as the Maps entry that matches the value in Lookups.
+ *
+ * For a hit, the corresponding sub-tensor of Values is included
+ * in the Output tensor. For a miss, the corresponding sub-tensor in
+ * Output must have zero values.
+ *
+ * For example, if Values has shape of [40, 200, 300],
+ * Keys should have a shape of [40]. If Lookups tensor has shape
+ * of [3], three slices are being concatenated, so the resulting tensor
+ * must have the shape of [3, 200, 300]. If the first entry in Lookups
+ * has the value 123456, that value must be located in Keys tensor.
+ * If the sixth entry of Keys contains 123456, the sixth slice of Values
+ * must be selected. If no entry in Keys has 123456, a slice of zeroes
+ * must be concatenated.
*
* Inputs:
- * * 0: Lookups. A 1-D int32 tensor with shape [ k ].
- * * 1: Keys. A 1-D int32 tensor with shape [ n ], *MUST* be sorted in
+ * * 0: Lookups. A 1-D {@link OperandType::TENSOR_INT32} tensor with
+ * shape [ k ].
+ * * 1: Keys. A 1-D {@link OperandType::TENSOR_INT32} tensor with shape
+ * [ n ]; Keys and Values pair represent a map, i.e., the ith element
+ * in Keys (Keys[i]) is the key to select the ith sub-tensor in Values
+ * (Values[i]), where 0 <= i <= n-1. Keys tensor *MUST* be sorted in
* ascending order.
- * * 2: Values. A tensor with shape [ n … ].
+ * * 2: Values. A tensor with shape of [ n, … ]; i.e., the first dimension
+ * must be n.
*
* Outputs:
* * 0: Output. A tensor with shape [ k …].
- * * 1: Hits. A uint8 tensor with shape [ k ] indicates whether the lookup
- * hits or not.
+ * * 1: Hits. A boolean tensor with shape [ k ] indicates whether the lookup
+ * hits (True) or not (False).
+ * Stored as {@link OperandType::TENSOR_QUANT8_ASYMM} with offset 0
+ * and scale 1.0f.
+ * A non-zero byte represents True, a hit. A zero indicates otherwise.
*/
HASHTABLE_LOOKUP = 10,
/**
- * Applies L2 normalization along a the depth dimension.
+ * Applies L2 normalization along the depth dimension.
+ *
+ * The values in the output tensor are computed as:
*
- * The values in output Tensor is computed as:
* output[batch, row, col, channel] =
* input[batch, row, col, channel] /
* sqrt(sum_{c} pow(input[batch, row, col, c], 2))
*
- * For x with more dimensions, independently normalizes each 1-D slice along dimension dim.
+ * For input tensor with more dimensions, independently normalizes each 1-D
+ * slice along dimension dim.
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * Supported tensor rank: 4, with "NHWC" data layout.
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
+ * Supported tensor rank: 4, with "NHWC" data layout (i.e., Num_samples,
+ * Height, Width, and Channels).
*
* Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input.
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth].
*
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth].
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth].
*/
L2_NORMALIZATION = 11,
/**
* Performs an 2-D L2 pooling operation.
*
- * The output dimensions are functions of the filter dimensions, stride, and padding.
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
*
- * The values in output Tensor is computed as:
* output[batch, row, col, channel] =
- * sqrt(sum_{i, j} pow(input[batch, row + i, col + j, channel], 2) / sum(1))
+ * sqrt(sum_{i, j} pow(input[batch, row + i, col + j, channel], 2) /
+ * sum(1))
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
* Supported tensor rank: 4, with "NHWC" data layout.
*
- * Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input.
- * 1: An INT32 value, specifying the padding on the left, in the ‘width’ dimension.
- * 2: An INT32 value, specifying the padding on the right,in the ‘width’ dimension.
- * 3: An INT32 value, specifying the padding on the top, in the ‘height’ dimension.
- * 4: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension.
- * 5: An INT32 value, specifying the output stride in the ‘width’ dimension.
- * 6: An INT32 value, specifying the output stride in the ‘height’ dimension.
- * 7: An INT32 value, specifying the filter width.
- * 8: An INT32 value, specifying the filter height.
- * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
- *
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth].
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+ * width.
+ * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+ * height.
+ * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+ * width.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+ * height.
+ * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth].
*/
L2_POOL_2D = 12,
/**
* Applies Local Response Normalization along the depth dimension.
*
- * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the last
- * dimension), and each vector is normalized independently. Within a given vector,
- * each component is divided by the weighted, squared sum of inputs within depth_radius.
+ * The 4-D input tensor is treated as a 3-D array of 1-D vectors (along the
+ * last dimension), and each vector is normalized independently. Within a
+ * given vector, each component is divided by the weighted, squared sum of
+ * inputs within depth_radius.
+ *
+ * The output is calculated using this formula:
*
- * In details:
- * sqr_sum[a, b, c, d] =
- * sum(pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2)
+ * sqr_sum[a, b, c, d] = sum(
+ * pow(input[a, b, c, d - depth_radius : d + depth_radius + 1], 2))
* output = input / pow((bias + alpha * sqr_sum), beta)
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
* Supported tensor rank: 4, with "NHWC" data layout.
*
* Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input.
- * 1: An INT32 value, specifying the radius of the normalization window.
- * 2: A FLOAT32 value, specifying the bias, must not be zero.
- * 3: A FLOAT32 value, specifying the scale factor, alpha.
- * 4: A FLOAT32 value, specifying the exponent, beta.
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the radius of
+ * the normalization window.
+ * * 2: An {@link OperandType::FLOAT32} scalar, specifying the bias, must
+ * not be zero.
+ * * 3: An {@link OperandType::FLOAT32} scalar, specifying the scale
+ * factor, alpha.
+ * * 4: An {@link OperandType::FLOAT32} scalar, specifying the exponent,
+ * beta.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
*/
LOCAL_RESPONSE_NORMALIZATION = 13,
/**
* Computes sigmoid activation on the input tensor element-wise.
*
- * In details:
+ * The output is calculated using this formula:
+ *
* output = 1 / (1 + exp(-input))
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the input.
+ * * 0: A tensor, specifying the input.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the scale must be 1.f / 256 and the zeroPoint must be 0.
*/
LOGISTIC = 14,
*
* * 1: Input. Dim.size >= 1, no restriction on DataType.
* * 2: Weight. Optional. Dim.size == 1, DataType: Float.
- * If not set, each input element is considered to have the same weight of
- * 1.0.
+ * If not set, each input element is considered to have the same weight
+ * of 1.0.
* Tensor[1].Dim[0] == Tensor[2].Dim[0]
* * 3: Type:
* Sparse: Value LSHProjectionType_SPARSE(=1).
* Computed bit vector is considered to be sparse.
- * Each output element is an int32 made up of multiple bits computed from
- * hash functions.
+ * Each output element is an int32 made up of multiple bits
+ * computed from hash functions.
*
* Dense: Value LSHProjectionType_DENSE(=2).
- * Computed bit vector is considered to be dense. Each output element
- * represents a bit and can take the value of either 0 or 1.
+ * Computed bit vector is considered to be dense. Each output
+ * element represents a bit and can take the value of either
+ * 0 or 1.
*
* Outputs:
* * 0: If the projection type is sparse:
LSH_PROJECTION = 15,
/**
- * Long short-term memory unit (LSTM) recurrent network layer.
+ * Performs a single time step in a Long Short-Term Memory (LSTM) layer
+ *
+ * The LSTM operation is described by the following equations.
*
- * The default non-peephole implementation is based on:
- * http://deeplearning.cs.cmu.edu/pdfs/Hochreiter97_lstm.pdf
+ * \f{eqnarray*}{
+ * i_t =& \sigma(W_{xi}x_t+W_{hi}h_{t-1}+W_{ci}C_{t-1}+b_i) & \\
+ * f_t =& \sigma(W_{xf}x_t+W_{hf}h_{t-1}+W_{cf}C_{t-1}+b_f) & \\
+ * C_t =& clip(f_t \odot C_{t-1} + i_t \odot
+ * g(W_{xc}x_t+W_{hc}h_{t-1}+b_c),\ t_{cell}) & \\
+ * o_t =& \sigma(W_{xo}x_t+W_{ho}h_{t-1}+W_{co}C_t+b_o) & \\
+ * & & \\
+ * & clip(W_{proj}(o_t \odot g(C_t))+b_{proj},\ t_{proj})
+ * & if\ there\ is\ a\ projection; \\
+ * h_t =& & \\
+ * & o_t \odot g(C_t) & otherwise. \\
+ * \f}
+ * Where:
+ * * \f$x_t\f$ is the input,
+ * * \f$i_t\f$ is the input gate,
+ * * \f$f_t\f$ is the forget gate,
+ * * \f$C_t\f$ is the cell state,
+ * * \f$o_t\f$ is the output,
+ * * \f$h_t\f$ is the output state,
+ * * \f$\sigma\f$ is the logistic sigmoid function,
+ * * \f$g\f$ is the cell input and cell output activation function, usually
+ * \f$tahn\f$,
+ * * \f$W_{xi}\f$ is the input-to-input weight matrix,
+ * * \f$W_{hi}\f$ is the recurrent to input weight matrix,
+ * * \f$W_{ci}\f$ is the cell-to-input weight matrix,
+ * * \f$b_i\f$ is the input gate bias,
+ * * \f$W_{xf}\f$ is the input-to-forget weight matrix,
+ * * \f$W_{hf}\f$ is the recurrent-to-forget weight matrix,
+ * * \f$W_{cf}\f$ is the cell-to-forget weight matrix,
+ * * \f$b_f\f$ is the forget gate bias,
+ * * \f$W_{xc}\f$ is the input-to-cell weight matrix,
+ * * \f$W_{hc}\f$ is the recurrent-to-cell weight matrix,
+ * * \f$b_c\f$ is the cell bias,
+ * * \f$W_{xo}\f$ is the input-to-output weight matrix,
+ * * \f$W_{ho}\f$ is the recurrent-to-output weight matrix,
+ * * \f$W_{co}\f$ is the cell-to-output weight matrix,
+ * * \f$b_o\f$ is the output gate bias,
+ * * \f$W_{proj}\f$ is the projection weight matrix,
+ * * \f$b_{proj}\f$ is the projection bias,
+ * * \f$t_{cell}\f$ is the threshold for clipping the cell state, and
+ * * \f$t_{proj}\f$ is the threshold for clipping the projected output.
+ * * \f$\odot\f$ is the
+ * <a href="https://en.wikipedia.org/wiki/Hadamard_product_(matrices)">
+ * Hadamard product</a> that takes two matrices and produces another
+ * matrix, each element of which is the product of the corresponding
+ * elements of the input matrices.
+ *
+ * The operation has the following independently optional inputs:
+ * * The input-to-input weights (\f$W_{xi}\f$), recurrent-to-input weights
+ * (\f$W_{hi}\f$), cell-to-input (\f$W_{ci}\f$) weights, and input gate
+ * bias (\f$b_i\f$) either all have values, or none of them have values
+ * (i.e., all set to null). If they have no values, coupling of input and
+ * forget gates (CIFG) is used, in which case the input gate (\f$i_t\f$)
+ * is calculated using the following equation instead.
+ * \f{eqnarray*}{
+ * i_t = 1 - f_t
+ * \f}
+ * * The cell-to-forget weights (\f$W_{cf}\f$) and cell-to-output weights
+ * (\f$W_{co}\f$) either both have values or neither of them have values.
+ * If they have values, the peephole optimization is used. Additionally,
+ * if CIFG is not used, cell-to-input weights (\f$W_{ci}\f$) is also
+ * required to have values for peephole optimization.
+ * * The projection weights (\f$W_{proj}\f$) is required only for the
+ * recurrent projection layer, and should otherwise have no value.
+ * * The projection bias (\f$b_{proj}\f$) may (but not required to) have a
+ * value if the recurrent projection layer exists, and should otherwise
+ * have no value.
+ *
+ * References:
+ *
+ * The default non-peephole non-CIFG implementation is based on:
+ * http://www.bioinf.jku.at/publications/older/2604.pdf
* S. Hochreiter and J. Schmidhuber. "Long Short-Term Memory". Neural
* Computation, 9(8):1735-1780, 1997.
*
- * The peephole implementation is based on:
+ * The peephole implementation and projection layer is based on:
* https://research.google.com/pubs/archive/43905.pdf
* Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory
- * recurrent neural network architectures for large scale acoustic modeling."
- * INTERSPEECH, 2014.
+ * recurrent neural network architectures for large scale acoustic
+ * modeling." INTERSPEECH, 2014.
+ * (However, the concept of peephole optimization was introduced in work
+ * prior to this paper.)
*
* The coupling of input and forget gate (CIFG) is based on:
* http://arxiv.org/pdf/1503.04069.pdf
* Greff et al. "LSTM: A Search Space Odyssey"
*
- * The class has the following independently optional inputs:
- * * If input gate (if CIFG): “input_to_forget_weights”,
- * “recurrent_to_input_weights”, “cell_to_input_weights”, “input_gate_bias”.
- * * If no peephole connections: “cell_to_input_weights”,
- * “cell_to_forget_weights”, “cell_to_output_weights”.
- * * If no projection layer: “projection_weights” and “projection_bias”.
- * * If no projection bias: “projection_bias”.
- *
- * Supported tensor types:
+ * Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
*
* Inputs:
- * * 0: Input.
- * A 2-D tensor of type T, of shape [batch_size, input_size], where
- * “batch_size” corresponds to the batching dimension, and “input_size”
- * is the size of the input.
- * * 1: input_to_input_weights.
- * A 2-D tensor of type T, of shape [num_units, input_size], where
- * “num_units” corresponds to the number of cell units.
- * * 2: input_to_forget_weights.
- * A 2-D tensor of type T, of shape [num_units, input_size].
- * * 3: input_to_cell_weights.
- * A 2-D tensor of type T, of shape [num_units, input_size].
- * * 4: input_to_output_weights.
- * A 2-D tensor of type T, of shape [num_units, input_size].
- * * 5: recurrent_to_input_weights.
- * A 2-D tensor of type T, of shape [num_units, output_size], where
- * “output_size” corresponds to either the number of cell units (i.e.,
- * “num_units”), or the second dimension of the “projection_weights”, if
- * defined.
- * * 6: recurrent_to_forget_weights.
- * A 2-D tensor of type T, of shape [num_units, output_size].
- * * 7: recurrent_to_cell_weights.
- * A 2-D tensor of type T, of shape [num_units, output_size].
- * * 8: recurrent_to_output_weights.
- * A 2-D tensor of type T, of shape [num_units, output_size].
- * * 9: cell_to_input_weights.
- * A 1-D tensor of type T, of shape [num_units].
- * * 10:cell_to_forget_weights.
- * A 1-D tensor of type T, of shape [num_units].
- * * 11:cell_to_output_weights.
- * A 1-D tensor of type T, of shape [num_units].
- * * 12:input_gate_bias.
- * A 1-D tensor of type T, of shape [num_units].
- * * 13:forget_gate_bias.
- * A 1-D tensor of type T, of shape [num_units].
- * * 14:cell_bias.
- * A 1-D tensor of type T, of shape [num_units].
- * * 15:output_gate_bias.
- * A 1-D tensor of type T, of shape [num_units].
- * * 16:projection_weights.
- * A 2-D tensor of type T, of shape [output_size, num_units].
- * * 17:projection_bias.
- * A 1-D tensor of type T, of shape [output_size].
- *
- * Parameters:
- * * 18:fused_activation_function.
- * An (optional) ActivationFunctionType indicating the activation
- * function.
- * If “NONE” is specified then it results in a linear activation.
- * * 19:cell_clip.
- * A clipping threshold for the cell state, such that values are bound
- * within [-cell_clip, cell_clip]. If set to 0.0 then clipping is
- * disabled.
- * * 20:proj_clip.
- * A clipping threshold for the output from the projection layer, such
- * that values are bound within [-proj_clip, proj_clip]. If set to 0.0
+ * * 0: The input (\f$x_t\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, input_size], where “batch_size” corresponds to the
+ * batching dimension, and “input_size” is the size of the input.
+ * * 1: The input-to-input weights (\f$W_{xi}\f$). Optional.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, input_size], where “num_units” corresponds to the
+ * number of cell units.
+ * * 2: The input-to-forget weights (\f$W_{xf}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, input_size].
+ * * 3: The input-to-cell weights (\f$W_{xc}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, input_size].
+ * * 4: The input-to-output weights (\f$W_{xo}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, input_size].
+ * * 5: The recurrent-to-input weights (\f$W_{hi}\f$). Optional.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, output_size], where “output_size” corresponds to either
+ * the number of cell units (i.e., “num_units”), or the second
+ * dimension of the “projection_weights”, if defined.
+ * * 6: The recurrent-to-forget weights (\f$W_{hf}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, output_size].
+ * * 7: The recurrent-to-cell weights (\f$W_{hc}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, output_size].
+ * * 8: The recurrent-to-output weights (\f$W_{ho}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, output_size].
+ * * 9: The cell-to-input weights (\f$W_{ci}\f$). Optional.
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 10:The cell-to-forget weights (\f$W_{cf}\f$). Optional.
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 11:The cell-to-output weights (\f$W_{co}\f$). Optional.
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 12:The input gate bias (\f$b_i\f$). Optional.
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 13:The forget gate bias (\f$b_f\f$).
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 14:The cell bias (\f$b_c\f$).
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 15:The output gate bias (\f$b_o\f$).
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 16:The projection weights (\f$W_{proj}\f$). Optional.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [output_size, num_units].
+ * * 17:The projection bias (\f$b_{proj}\f$). Optional.
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [output_size].
+ * * 18:The output state (in) (\f$h_{t-1}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, output_size].
+ * * 19:The cell state (in) (\f$C_{t-1}\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units].
+ * * 20:The activation function (\f$g\f$).
+ * A value indicating the activation function:
+ * <ul>
+ * <li>0: None;
+ * <li>1: Relu;
+ * <li>3: Relu6;
+ * <li>4: Tanh;
+ * <li>6: Sigmoid.
+ * </ul>
+ * * 21:The clipping threshold (\f$t_{cell}\f$) for the cell state, such
+ * that values are bound within [-cell_clip, cell_clip]. If set to 0.0
* then clipping is disabled.
+ * * 22:The clipping threshold (\f$t_{proj}\f$) for the output from the
+ * projection layer, such that values are bound within
+ * [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
*
* Outputs:
- * * 0: scratch_buffer.
- * A 3-D tensor of type T, of shape [batch_size, num_cell, 4].
- * * 1: output_state.
- * A 2-D tensor of type T, of shape [batch_size, output_size].
- * * 2: cell_state.
- * A 2-D tensor of type T, of shape [batch_size, num_units].
- * * 3: output.
- * A 2-D tensor of type T, of shape [batch_size, output_size]. This is
- * effectively the same as the current “output_state” value.
+ * * 0: The scratch buffer.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units * 4] with CIFG, or
+ * [batch_size, num_units * 3] without CIFG.
+ * * 1: The output state (out) (\f$h_t\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, output_size].
+ * * 2: The cell state (out) (\f$C_t\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units].
+ * * 3: The output (\f$o_t\f$).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, output_size]. This is effectively the same as the
+ * current “output state (out)” value.
*/
LSTM = 16,
/**
* Performs an 2-D max pooling operation.
*
- * The output dimensions are functions of the filter dimensions, stride, and padding.
+ * The output dimensions are functions of the filter dimensions, stride, and
+ * padding.
+ *
+ * The values in the output tensor are computed as:
*
- * The values in output Tensor is computed as:
* output[batch, row, col, channel] =
* max_{i, j} (input[batch, row + i, col + j, channel])
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: 4, with "NHWC" data layout.
*
- * Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input.
- * 1: An INT32 value, specifying the padding on the left, in the ‘width’ dimension.
- * 2: An INT32 value, specifying the padding on the right,in the ‘width’ dimension.
- * 3: An INT32 value, specifying the padding on the top, in the ‘height’ dimension.
- * 4: An INT32 value, specifying the padding on the bottom, in the ‘height’ dimension.
- * 5: An INT32 value, specifying the output stride in the ‘width’ dimension.
- * 6: An INT32 value, specifying the output stride in the ‘height’ dimension.
- * 7: An INT32 value, specifying the filter width.
- * 8: An INT32 value, specifying the filter height.
- * 9: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
- *
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, out_height, out_width, depth].
+ * Both explicit padding and implicit padding are supported.
+ *
+ * Inputs (explicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the left, in the ‘width’ dimension.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the right, in the ‘width’ dimension.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the top, in the ‘height’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the padding on
+ * the bottom, in the ‘height’ dimension.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 6: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 7: An {@link OperandType::INT32} scalar, specifying the filter
+ * width.
+ * * 8: An {@link OperandType::INT32} scalar, specifying the filter
+ * height.
+ * * 9: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Inputs (implicit padding):
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the implicit
+ * padding scheme, has to be one of the
+ * following values: {0 (NONE), 1 (SAME), 2 (VALID)}.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘width’ dimension.
+ * * 3: An {@link OperandType::INT32} scalar, specifying the stride when
+ * walking through input in the ‘height’ dimension.
+ * * 4: An {@link OperandType::INT32} scalar, specifying the filter
+ * width.
+ * * 5: An {@link OperandType::INT32} scalar, specifying the filter
+ * height.
+ * * 6: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
+ *
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, out_height, out_width, depth].
*/
MAX_POOL_2D = 17,
/**
- * Multiplies two tensors, elment-wise.
+ * Multiplies two tensors, element-wise.
*
- * Takes two input tensors of identical type and compatible dimensions. The output
- * is the product of both input tensors, optionally modified by an activation function.
+ * Takes two input tensors of identical {@link OperandType} and compatible
+ * dimensions. The output is the product of both input tensors, optionally
+ * modified by an activation function.
*
* Two dimensions are compatible when:
* 1. they are equal, or
* 2. one of them is 1
*
- * The size of the resulting output is the maximum size along each dimension of the
- * input operands. It starts with the trailing dimensions, and works its way forward.
+ * The size of the resulting output is the maximum size along each dimension
+ * of the input operands. It starts with the trailing dimensions, and works
+ * its way forward.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: A tensor.
- * 1: A tensor of the same type, and compatible dimensions as input0.
- * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
+ * * 0: A tensor.
+ * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
*
- * Ouputs:
- * 0: The product, a tensor of the same type as input0.
+ * Outputs:
+ * * 0: The product, a tensor of the same {@link OperandType} as input0.
+ * For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the following condition must be satisfied:
+ * output_scale > input1_scale * input2_scale.
*/
MUL = 18,
/**
* Computes rectified linear activation on the input tensor element-wise.
*
- * In details:
+ * The output is calculated using this formula:
+ *
* output = max(0, input)
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the input.
+ * * 0: A tensor, specifying the input.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
*/
RELU = 19,
/**
* Computes rectified linear 1 activation on the input tensor element-wise.
*
- * In details:
+ * The output is calculated using this formula:
+ *
* output = min(1.f, max(-1.f, input))
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the input.
+ * * 0: A tensor, specifying the input.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
*/
RELU1 = 20,
/**
* Computes rectified linear 6 activation on the input tensor element-wise.
*
- * In details:
+ * The output is calculated using this formula:
+ *
* output = min(6, max(0, input))
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the input.
+ * * 0: A tensor, specifying the input.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
*/
RELU6 = 21,
/**
* Reshapes a tensor.
*
- * Given tensor, this operation returns a tensor that has the same values as tensor,
- * but with a newly specified shape.
+ * Given tensor, this operation returns a tensor that has the same values as
+ * tensor, but with a newly specified shape.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the tensor to be reshaped.
- * 1: A 1-D tensor of type {@link OperandType::TENSOR_INT32}, defining the shape
- * of the output tensor. The number of elements implied by shape must be the same
- * as the number of elements in the input tensor.
+ * * 0: A tensor, specifying the tensor to be reshaped.
+ * * 1: A 1-D tensor of {@link OperandType::TENSOR_INT32}, defining the
+ * shape of the output tensor. The number of elements implied by shape
+ * must be the same as the number of elements in the input tensor.
*
- * Ouputs:
- * 0: The output tensor, of shape specified by the input shape.
+ * Outputs:
+ * * 0: The output tensor, of shape specified by the input shape.
*/
RESHAPE = 22,
/**
* Resizes images to given size using the bilinear interpretation.
*
- * Resized images will be distorted if their original aspect ratio is not the same as input.
+ * Resized images must be distorted if their output aspect ratio is not the
+ * same as input aspect ratio. The corner pixels of output may not be the
+ * same as corner pixels of input.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
* Supported tensor rank: 4, with "NHWC" data layout.
*
* Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying the input.
- * 1: An INT32 value, specifying the output width of the output tensor.
- * 2: An INT32 value, specifying the output height of the output tensor.
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
+ * the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the output
+ * height of the output tensor.
+ * * 2: An {@link OperandType::INT32} scalar, specifying the output
+ * width of the output tensor.
*
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batches, new_height, new_width, depth].
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape
+ * [batches, new_height, new_width, depth].
*/
RESIZE_BILINEAR = 23,
* A basic recurrent neural network layer.
*
* This layer implements the operation:
- * outputs = state = activation(inputs * input_weights + state * recurrent_weights + bias)
+ * outputs = state = activation(inputs * input_weights +
+ * state * recurrent_weights + bias)
*
* Where:
* * “input_weights” is a weight matrix that multiplies the inputs;
* * “activation” is the function passed as the “fused_activation_function”
* argument (if not “NONE”).
*
- * Supported tensor types:
+ * Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
*
* Inputs:
* * 0: input.
- * A 2-D tensor of type T, of shape [batch_size, input_size], where
- * “batch_size” corresponds to the batching dimension, and “input_size” is
- * the size of the input.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32} of shape
+ * [batch_size, input_size], where “batch_size” corresponds to the
+ * batching dimension, and “input_size” is the size of the input.
* * 1: weights.
- * A 2-D tensor of type T, of shape [num_units, input_size], where
- * “num_units” corresponds to the number of units.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, input_size], where “num_units” corresponds to the
+ * number of units.
* * 2: recurrent_weights.
- * A 2-D tensor of type T, of shape [num_units, num_units], with columns
- * corresponding to the weights from each unit.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, num_units], with columns corresponding to the weights
+ * from each unit.
* * 3: bias.
- * A 1-D tensor of type T, of shape [num_units].
- *
- * For FLOAT32 input tensor, bias must also be FLOAT32.
- * For UINT8 input tensor, bias must be INT32.
- *
- * Parameters
- * * 4: fused_activation_function.
- * An (optional) ActivationFunctionType indicating the activation
- * function. If “NONE” is specified then it results in a linear
- * activation.
- *
- * * 5: Hidden state.
- * A 2-D tensor of type T, of shape [batch_size, num_units].
+ * A 1-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units].
+ * * 4: hidden state (in).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units].
+ * * 5: fused_activation_function.
+ * An optional {@link FusedActivationFunc} value indicating the
+ * activation function. If “NONE” is specified then it results in a
+ * linear activation.
*
* Outputs:
- * * 0: output.
- * A 2-D tensor of type T, of shape [batch_size, num_units]. This is
- * effectively the same as the current state value.
+ * * 0: hidden state (out).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units].
+ *
+ * * 1: output.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units]. This is effectively the same as the
+ * current state value.
*/
RNN = 24,
/**
- * Computes the softmax activation on the input tensor element-wise, per batch, by
- * normalizing the input vector so the maximum coefficient is zero.
+ * Computes the softmax activation on the input tensor element-wise, per
+ * batch, by normalizing the input vector so the maximum coefficient is
+ * zero.
+ *
+ * The output is calculated using this formula:
*
- * In details:
* output[batch, i] =
* exp((input[batch, i] - max(input[batch, :])) * beta) /
* sum_{k}{exp((input[batch, k] - max(input[batch, :])) * beta)}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: 2 or 4.
*
* Inputs:
- * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
- * 1: A FLOAT32 value, specifying the scaling factor for the exponent, beta.
+ * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+ * * 1: An {@link OperandType::FLOAT32} scalar, specifying the positive
+ * scaling factor for the exponent, beta.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
+ * For {@link OperandType::TENSOR_QUANT8_ASYMM},
+ * the scale must be 1.f / 256 and the zeroPoint must be 0.
*/
SOFTMAX = 25,
/**
* Rearranges blocks of spatial data, into depth.
*
- * More specifically, this op outputs a copy of the input tensor where values from
- * the height and width dimensions are moved to the depth dimension.
- * The value block_size indicates the input block size and how the data is moved.
+ * More specifically, this op outputs a copy of the input tensor where
+ * values from the height and width dimensions are moved to the depth
+ * dimension. The value block_size indicates the input block size and how
+ * the data is moved.
*
- * Chunks of data of size block_size * block_size from depth are rearranged into
- * non-overlapping blocks of size block_size x block_size.
+ * Chunks of data of size block_size * block_size from depth are rearranged
+ * into non-overlapping blocks of size block_size x block_size.
*
* The depth of the output tensor is input_depth * block_size * block_size.
* The input tensor's height and width must be divisible by block_size.
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: 4, with "NHWC" data layout.
*
* Inputs:
- * 0: A 4-D tensor, of shape [batches, height, width, depth_in], specifying the input.
- * 1: An INT32 value, specifying the block_size. block_size must be >=1 and
- * block_size must be a divisor of both the input height and width.
+ * * 0: A 4-D tensor, of shape [batches, height, width, depth_in],
+ * specifying the input.
+ * * 1: An {@link OperandType::INT32} scalar, specifying the block_size.
+ * block_size must be >=1 and block_size must be a divisor of both the
+ * input height and width.
*
- * Ouputs:
- * 0: The output 4-D tensor, of shape [batch, height/block_size, width/block_size,
- * depth*block_size*block_size].
+ * Outputs:
+ * * 0: The output 4-D tensor, of shape [batch, height/block_size,
+ * width/block_size, depth*block_size*block_size].
*/
SPACE_TO_DEPTH = 26,
* INTERSPEECH, 2015.
*
* It processes the incoming input using a 2-stage filtering mechanism:
- * * stage 1 performs filtering on the "features" dimension, whose outputs get
- * pushed into a memory of fixed-size memory_size.
+ * * stage 1 performs filtering on the "features" dimension, whose outputs
+ * get pushed into a memory of fixed-size memory_size.
* * stage 2 performs filtering on the "time" dimension of the memory_size
* memoized outputs of stage 1.
*
* Specifically, for rank 1, this layer implements the operation:
*
- * memory = push(conv1d(inputs, weights_feature, feature_dim, "VALID"));
- * outputs = activation(memory * weights_time + bias);
+ * memory = push(conv1d(inputs, weights_feature, feature_dim,
+ * "PADDING_VALID"));
+ * outputs = activation(memory * weights_time + bias);
*
* Where:
* * “weights_feature” is a weights matrix that processes the inputs (by
- * convolving the input with every “feature filter”), and whose outputs get
- * pushed, stacked in order, into the fixed-size “memory” (the oldest entry
- * gets dropped);
+ * convolving the input with every “feature filter”), and whose outputs
+ * get pushed, stacked in order, into the fixed-size “memory” (the oldest
+ * entry gets dropped);
* * “weights_time” is a weights matrix that processes the “memory” (by a
* batched matrix multiplication on the num_units);
* * “bias” is an optional bias vector (added to each output vector in the
* Each rank adds a dimension to the weights matrices by means of stacking
* the filters.
*
- * Supported tensor types:
+ * Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
*
* Inputs:
* * 0: input.
- * A 2-D tensor of type T, of shape [batch_size, input_size], where
- * “batch_size” corresponds to the batching dimension, and “input_size” is
- * the size of the input.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, input_size], where “batch_size” corresponds to the
+ * batching dimension, and “input_size” is the size of the input.
* * 1: weights_feature.
- * A 2-D tensor of type T, of shape [num_units, input_size], where
- * “num_units” corresponds to the number of units.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, input_size], where “num_units” corresponds to the
+ * number of units.
* * 2: weights_time.
- * A 2-D tensor of type T, of shape [num_units, memory_size], where
- * “memory_size” corresponds to the fixed-size of the memory.
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [num_units, memory_size], where “memory_size” corresponds to the
+ * fixed-size of the memory.
* * 3: bias.
- * A optional 1-D tensor of type T, of shape [num_units].
- *
- * For FLOAT32 input tensor, bias must also be FLOAT32.
- * For UINT8 input tensor, bias must be INT32.
- *
- * Parameters:
- * * 4: rank.
+ * An optional 1-D tensor of {@link OperandType::TENSOR_FLOAT32},
+ * of shape [num_units].
+ * * 4: state (in).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, (memory_size - 1) * num_units * rank].
+ * * 5: rank.
* The rank of the SVD approximation.
- * * 5: fused_activation_function.
- * An (optional) ActivationFunctionType indicating the activation function.
- * If “NONE” is specified then it results in a linear activation.
+ * * 6: fused_activation_function.
+ * An optional {@link FusedActivationFunc} value indicating the
+ * activation function. If “NONE” is specified then it results in a
+ * linear activation.
*
* Outputs:
- * * 0: state.
- * A 2-D tensor of type T, of shape [batch_size, (memory_size - 1) * num_units * rank].
+ * * 0: state (out).
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, (memory_size - 1) * num_units * rank].
* * 1: output.
- * A 2-D tensor of type T, of shape [batch_size, num_units].
+ * A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
+ * [batch_size, num_units].
*/
SVDF = 27,
/**
* Computes hyperbolic tangent of input tensor element-wise.
*
- * In details:
+ * The output is calculated using this formula:
+ *
* output = tanh(input)
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
* Supported tensor rank: up to 4.
*
* Inputs:
- * 0: A tensor, specifying the input.
+ * * 0: A tensor, specifying the input.
*
- * Ouputs:
- * 0: The output tensor of same shape as input0.
+ * Outputs:
+ * * 0: The output tensor of same shape as input0.
*/
TANH = 28,
/**
* OEM specific operation.
*
- * This operation is OEM specific. It should only be used for OEM applications.
+ * This operation is OEM specific. It should only be used for OEM
+ * applications.
*/
OEM_OPERATION = 10000,
};
*/
enum OperandLifeTime : int32_t {
/**
- * The operand is internal to the model. It's created by an operation
- * and consumed by other operations.
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations.
*/
TEMPORARY_VARIABLE,
CONSTANT_REFERENCE,
/**
- * The operand does not have a value. This is valid only for optional arguments
- * of operations.
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
*/
NO_VALUE,
};
vec<uint32_t> dimensions;
/**
- * The number of operations that use this operand as input.
+ * The number of times this operand appears as an operation input.
+ *
+ * (For example, if this operand appears once in one operation's
+ * input list, and three times in another operation's input list,
+ * then numberOfConsumers = 4.)
*/
uint32_t numberOfConsumers;
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or NO_VALUE:
- * - All the fields will be 0.
+ * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_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.
*/
struct 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.
+ * 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.
*/
bool hasNoValue;
/**
* 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, 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.
*/
vec<uint32_t> dimensions;
};
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 54dd14aba350294ae12d24e67571b6ed45eabd3c..e28113bcdc2096d017ddb516a5743d0ce2aab90d 100644 (file)
name: "VtsHalNeuralnetworksTest_utils",
srcs: [
"Callbacks.cpp",
- "Models.cpp",
"GeneratedTestHarness.cpp",
],
defaults: ["VtsHalTargetTestDefaults"],
cc_test {
name: "VtsHalNeuralnetworksV1_0TargetTest",
srcs: [
- "VtsHalNeuralnetworksV1_0.cpp",
- "VtsHalNeuralnetworksV1_0BasicTest.cpp",
- "VtsHalNeuralnetworksV1_0GeneratedTest.cpp",
+ "BasicTests.cpp",
+ "GeneratedTests.cpp",
+ "ValidateModel.cpp",
+ "ValidateRequest.cpp",
+ "ValidationTests.cpp",
+ "VtsHalNeuralnetworks.cpp",
],
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
- "android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// create device test
+TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+
+// status test
+TEST_F(NeuralnetworksHidlTest, StatusTest) {
+ Return<DeviceStatus> status = device->getStatus();
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
+}
+
+// initialization
+TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+ Return<void> ret =
+ device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
+ EXPECT_EQ(ErrorStatus::NONE, status);
+ EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
+ EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
+ EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
+ EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
+ });
+ EXPECT_TRUE(ret.isOk());
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.h b/neuralnetworks/1.0/vts/functional/Callbacks.h
index 0e2ffb324a61952f2095b19920b2bc76f7a70e24..570a4fb74a8bca3ada5115e862e0aac1a23742cf 100644 (file)
namespace V1_0 {
namespace implementation {
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
/**
* The CallbackBase class is used internally by the NeuralNetworks runtime to
* synchronize between different threads. An asynchronous task is launched
* "notify". This "notify" call awakens any client threads waiting on the
* callback object.
*
- * callback object. When the asynchronous task has finished its workload or has
- * failed to launch, it must immediately call "notify", awakening any client
- * threads waiting on the callback object.
- *
* The CallbackBase class implements some of the base synchronization common to
* both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL
* callback class must inherit from CallbackBase as well as the HIDL callback
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 8646a4cbb0d3dda176b5bebee39af22043b7422e..0682ab95b28e5eab7a65482de747d7eb9d325b7d 100644 (file)
namespace generated_tests {
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-using ::generated_tests::filter;
-using ::generated_tests::for_all;
-using ::generated_tests::for_each;
-using ::generated_tests::resize_accordingly;
-using ::generated_tests::MixedTyped;
-using ::generated_tests::MixedTypedExampleType;
-using ::generated_tests::Float32Operands;
-using ::generated_tests::Int32Operands;
-using ::generated_tests::Quant8Operands;
-using ::generated_tests::compare;
+using ::test_helper::filter;
+using ::test_helper::for_all;
+using ::test_helper::for_each;
+using ::test_helper::resize_accordingly;
+using ::test_helper::MixedTyped;
+using ::test_helper::MixedTypedExampleType;
+using ::test_helper::Float32Operands;
+using ::test_helper::Int32Operands;
+using ::test_helper::Quant8Operands;
+using ::test_helper::compare;
template <typename T>
void copy_back_(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
@@ -179,7 +179,7 @@ void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool
}
}
-void Execute(sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
+void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
std::function<bool(int)> is_ignored,
const std::vector<MixedTypedExampleType>& examples) {
V1_0::Model model = create_model();
@@ -223,7 +223,7 @@ void Execute(sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_
EvaluatePreparedModel(preparedModel, is_ignored, examples);
}
-void Execute(sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
+void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
std::function<bool(int)> is_ignored,
const std::vector<MixedTypedExampleType>& examples) {
V1_1::Model model = create_model();
@@ -242,8 +242,8 @@ void Execute(sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_
// launch prepare model
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTests.cpp
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+
+namespace generated_tests {
+using ::test_helper::MixedTypedExampleType;
+extern void Execute(const sp<V1_0::IDevice>&, std::function<V1_0::Model(void)>,
+ std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
+} // namespace generated_tests
+
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
+
+// Mixed-typed examples
+typedef test_helper::MixedTypedExampleType MixedTypedExample;
+
+// in frameworks/ml/nn/runtime/tests/generated/
+#include "all_generated_V1_0_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Models.cpp b/neuralnetworks/1.0/vts/functional/Models.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 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_hidl_hal_test"
-
-#include "Models.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-#include <vector>
-
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-
-// create a valid model
-V1_1::Model createValidTestModel_1_1() {
- const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
- const uint32_t size = operand2Data.size() * sizeof(float);
-
- const uint32_t operand1 = 0;
- const uint32_t operand2 = 1;
- const uint32_t operand3 = 2;
- const uint32_t operand4 = 3;
-
- const std::vector<Operand> operands = {
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {1, 2, 2, 1},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- },
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {1, 2, 2, 1},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 0, .length = size},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)},
- },
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {1, 2, 2, 1},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_OUTPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- },
- };
-
- const std::vector<Operation> operations = {{
- .type = OperationType::ADD, .inputs = {operand1, operand2, operand3}, .outputs = {operand4},
- }};
-
- const std::vector<uint32_t> inputIndexes = {operand1};
- const std::vector<uint32_t> outputIndexes = {operand4};
- std::vector<uint8_t> operandValues(
- reinterpret_cast<const uint8_t*>(operand2Data.data()),
- reinterpret_cast<const uint8_t*>(operand2Data.data()) + size);
- int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
- operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
- reinterpret_cast<const uint8_t*>(&activation[1]));
-
- const std::vector<hidl_memory> pools = {};
-
- return {
- .operands = operands,
- .operations = operations,
- .inputIndexes = inputIndexes,
- .outputIndexes = outputIndexes,
- .operandValues = operandValues,
- .pools = pools,
- };
-}
-
-// create first invalid model
-V1_1::Model createInvalidTestModel1_1_1() {
- Model model = createValidTestModel_1_1();
- model.operations[0].type = static_cast<OperationType>(0xDEADBEEF); /* INVALID */
- return model;
-}
-
-// create second invalid model
-V1_1::Model createInvalidTestModel2_1_1() {
- Model model = createValidTestModel_1_1();
- const uint32_t operand1 = 0;
- const uint32_t operand5 = 4; // INVALID OPERAND
- model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */});
- return model;
-}
-
-V1_0::Model createValidTestModel_1_0() {
- V1_1::Model model = createValidTestModel_1_1();
- return nn::convertToV1_0(model);
-}
-
-V1_0::Model createInvalidTestModel1_1_0() {
- V1_1::Model model = createInvalidTestModel1_1_1();
- return nn::convertToV1_0(model);
-}
-
-V1_0::Model createInvalidTestModel2_1_0() {
- V1_1::Model model = createInvalidTestModel2_1_1();
- return nn::convertToV1_0(model);
-}
-
-// create a valid request
-Request createValidTestRequest() {
- std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
- std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
-
- // prepare inputs
- uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
- uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float));
- std::vector<RequestArgument> inputs = {{
- .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {},
- }};
- std::vector<RequestArgument> outputs = {{
- .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
- }};
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
- return {};
- }
-
- // load data
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
- if (inputMemory.get() == nullptr || outputMemory.get() == nullptr) {
- return {};
- }
- float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer()));
- float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
- if (inputPtr == nullptr || outputPtr == nullptr) {
- return {};
- }
- inputMemory->update();
- outputMemory->update();
- std::copy(inputData.begin(), inputData.end(), inputPtr);
- std::copy(outputData.begin(), outputData.end(), outputPtr);
- inputMemory->commit();
- outputMemory->commit();
-
- return {.inputs = inputs, .outputs = outputs, .pools = pools};
-}
-
-// create first invalid request
-Request createInvalidTestRequest1() {
- Request request = createValidTestRequest();
- const uint32_t INVALID = 2;
- std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
- uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
- request.inputs[0].location = {
- .poolIndex = INVALID /* INVALID */, .offset = 0, .length = inputSize};
- return request;
-}
-
-// create second invalid request
-Request createInvalidTestRequest2() {
- Request request = createValidTestRequest();
- request.inputs[0].dimensions = std::vector<uint32_t>({1, 2, 3, 4, 5, 6, 7, 8} /* INVALID */);
- return request;
-}
-
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/Models.h b/neuralnetworks/1.0/vts/functional/Models.h
index 93982351f4aecc629c774b02c4a3ca4e5f039a42..751ab32aeaf938fca90233f3934d1db59f2afffd 100644 (file)
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
* limitations under the License.
*/
+#ifndef VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
+#define VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
+
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include <android/hardware/neuralnetworks/1.1/types.h>
+#include "TestHarness.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
namespace android {
namespace hardware {
namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+using MixedTypedExample = test_helper::MixedTypedExampleType;
-// create V1_1 model
-V1_1::Model createValidTestModel_1_1();
-V1_1::Model createInvalidTestModel1_1_1();
-V1_1::Model createInvalidTestModel2_1_1();
+#define FOR_EACH_TEST_MODEL(FN) \
+ FN(add_broadcast_quant8) \
+ FN(add) \
+ FN(add_quant8) \
+ FN(avg_pool_float_1) \
+ FN(avg_pool_float_2) \
+ FN(avg_pool_float_3) \
+ FN(avg_pool_float_4) \
+ FN(avg_pool_float_5) \
+ FN(avg_pool_quant8_1) \
+ FN(avg_pool_quant8_2) \
+ FN(avg_pool_quant8_3) \
+ FN(avg_pool_quant8_4) \
+ FN(avg_pool_quant8_5) \
+ FN(concat_float_1) \
+ FN(concat_float_2) \
+ FN(concat_float_3) \
+ FN(concat_quant8_1) \
+ FN(concat_quant8_2) \
+ FN(concat_quant8_3) \
+ FN(conv_1_h3_w2_SAME) \
+ FN(conv_1_h3_w2_VALID) \
+ FN(conv_3_h3_w2_SAME) \
+ FN(conv_3_h3_w2_VALID) \
+ FN(conv_float_2) \
+ FN(conv_float_channels) \
+ FN(conv_float_channels_weights_as_inputs) \
+ FN(conv_float_large) \
+ FN(conv_float_large_weights_as_inputs) \
+ FN(conv_float) \
+ FN(conv_float_weights_as_inputs) \
+ FN(conv_quant8_2) \
+ FN(conv_quant8_channels) \
+ FN(conv_quant8_channels_weights_as_inputs) \
+ FN(conv_quant8_large) \
+ FN(conv_quant8_large_weights_as_inputs) \
+ FN(conv_quant8) \
+ FN(conv_quant8_overflow) \
+ FN(conv_quant8_overflow_weights_as_inputs) \
+ FN(conv_quant8_weights_as_inputs) \
+ FN(depth_to_space_float_1) \
+ FN(depth_to_space_float_2) \
+ FN(depth_to_space_float_3) \
+ FN(depth_to_space_quant8_1) \
+ FN(depth_to_space_quant8_2) \
+ FN(depthwise_conv2d_float_2) \
+ FN(depthwise_conv2d_float_large_2) \
+ FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
+ FN(depthwise_conv2d_float_large) \
+ FN(depthwise_conv2d_float_large_weights_as_inputs) \
+ FN(depthwise_conv2d_float) \
+ FN(depthwise_conv2d_float_weights_as_inputs) \
+ FN(depthwise_conv2d_quant8_2) \
+ FN(depthwise_conv2d_quant8_large) \
+ FN(depthwise_conv2d_quant8_large_weights_as_inputs) \
+ FN(depthwise_conv2d_quant8) \
+ FN(depthwise_conv2d_quant8_weights_as_inputs) \
+ FN(depthwise_conv) \
+ FN(dequantize) \
+ FN(embedding_lookup) \
+ FN(floor) \
+ FN(fully_connected_float_2) \
+ FN(fully_connected_float_large) \
+ FN(fully_connected_float_large_weights_as_inputs) \
+ FN(fully_connected_float) \
+ FN(fully_connected_float_weights_as_inputs) \
+ FN(fully_connected_quant8_2) \
+ FN(fully_connected_quant8_large) \
+ FN(fully_connected_quant8_large_weights_as_inputs) \
+ FN(fully_connected_quant8) \
+ FN(fully_connected_quant8_weights_as_inputs) \
+ FN(hashtable_lookup_float) \
+ FN(hashtable_lookup_quant8) \
+ FN(l2_normalization_2) \
+ FN(l2_normalization_large) \
+ FN(l2_normalization) \
+ FN(l2_pool_float_2) \
+ FN(l2_pool_float_large) \
+ FN(l2_pool_float) \
+ FN(local_response_norm_float_1) \
+ FN(local_response_norm_float_2) \
+ FN(local_response_norm_float_3) \
+ FN(local_response_norm_float_4) \
+ FN(logistic_float_1) \
+ FN(logistic_float_2) \
+ FN(logistic_quant8_1) \
+ FN(logistic_quant8_2) \
+ FN(lsh_projection_2) \
+ FN(lsh_projection) \
+ FN(lsh_projection_weights_as_inputs) \
+ FN(lstm2) \
+ FN(lstm2_state2) \
+ FN(lstm2_state) \
+ FN(lstm3) \
+ FN(lstm3_state2) \
+ FN(lstm3_state3) \
+ FN(lstm3_state) \
+ FN(lstm) \
+ FN(lstm_state2) \
+ FN(lstm_state) \
+ FN(max_pool_float_1) \
+ FN(max_pool_float_2) \
+ FN(max_pool_float_3) \
+ FN(max_pool_float_4) \
+ FN(max_pool_quant8_1) \
+ FN(max_pool_quant8_2) \
+ FN(max_pool_quant8_3) \
+ FN(max_pool_quant8_4) \
+ FN(mobilenet_224_gender_basic_fixed) \
+ FN(mobilenet_quantized) \
+ FN(mul_broadcast_quant8) \
+ FN(mul) \
+ FN(mul_quant8) \
+ FN(mul_relu) \
+ FN(relu1_float_1) \
+ FN(relu1_float_2) \
+ FN(relu1_quant8_1) \
+ FN(relu1_quant8_2) \
+ FN(relu6_float_1) \
+ FN(relu6_float_2) \
+ FN(relu6_quant8_1) \
+ FN(relu6_quant8_2) \
+ FN(relu_float_1) \
+ FN(relu_float_2) \
+ FN(relu_quant8_1) \
+ FN(relu_quant8_2) \
+ FN(reshape) \
+ FN(reshape_quant8) \
+ FN(reshape_quant8_weights_as_inputs) \
+ FN(reshape_weights_as_inputs) \
+ FN(resize_bilinear_2) \
+ FN(resize_bilinear) \
+ FN(rnn) \
+ FN(rnn_state) \
+ FN(softmax_float_1) \
+ FN(softmax_float_2) \
+ FN(softmax_quant8_1) \
+ FN(softmax_quant8_2) \
+ FN(space_to_depth_float_1) \
+ FN(space_to_depth_float_2) \
+ FN(space_to_depth_float_3) \
+ FN(space_to_depth_quant8_1) \
+ FN(space_to_depth_quant8_2) \
+ FN(svdf2) \
+ FN(svdf) \
+ FN(svdf_state) \
+ FN(tanh)
-// create V1_0 model
-V1_0::Model createValidTestModel_1_0();
-V1_0::Model createInvalidTestModel1_1_0();
-V1_0::Model createInvalidTestModel2_1_0();
+#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
+ namespace function { \
+ extern std::vector<MixedTypedExample> examples; \
+ Model createTestModel(); \
+ }
-// create the request
-V1_0::Request createValidTestRequest();
-V1_0::Request createInvalidTestRequest1();
-V1_0::Request createInvalidTestRequest2();
+FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
+#undef FORWARD_DECLARE_GENERATED_OBJECTS
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
+
+#endif // VTS_HAL_NEURALNETWORKS_V1_0_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
+ const V1_0::Model& model) {
+ SCOPED_TRACE(message + " [getSupportedOperations]");
+
+ Return<void> ret =
+ device->getSupportedOperations(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+ EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+ });
+ EXPECT_TRUE(ret.isOk());
+}
+
+static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
+ const V1_0::Model& model) {
+ SCOPED_TRACE(message + " [prepareModel]");
+
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+ ASSERT_EQ(nullptr, preparedModel.get());
+}
+
+// Primary validation function. This function will take a valid model, apply a
+// mutation to it to invalidate the model, then pass it to interface calls that
+// use the model. Note that the model here is passed by value, and any mutation
+// to the model does not leave this function.
+static void validate(const sp<IDevice>& device, const std::string& message, V1_0::Model model,
+ const std::function<void(Model*)>& mutation) {
+ mutation(&model);
+ validateGetSupportedOperations(device, message, model);
+ validatePrepareModel(device, message, model);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+ if (vec) {
+ std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+ vec->resize(vec->size() - 1);
+ }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+ // assume vec is valid
+ const uint32_t index = vec->size();
+ vec->resize(index + 1);
+ (*vec)[index] = value;
+ return index;
+}
+
+static uint32_t addOperand(Model* model) {
+ return hidl_vec_push_back(&model->operands,
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_INPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ });
+}
+
+static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
+ uint32_t index = addOperand(model);
+ model->operands[index].numberOfConsumers = 1;
+ model->operands[index].lifetime = lifetime;
+ return index;
+}
+
+///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
+
+static const int32_t invalidOperandTypes[] = {
+ static_cast<int32_t>(OperandType::FLOAT32) - 1, // lower bound fundamental
+ static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental
+ static_cast<int32_t>(OperandType::OEM) - 1, // lower bound OEM
+ static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM
+};
+
+static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (int32_t invalidOperandType : invalidOperandTypes) {
+ const std::string message = "mutateOperandTypeTest: operand " +
+ std::to_string(operand) + " set to value " +
+ std::to_string(invalidOperandType);
+ validate(device, message, model, [operand, invalidOperandType](Model* model) {
+ model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE OPERAND RANK /////////////////////////
+
+static uint32_t getInvalidRank(OperandType type) {
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ return 1;
+ case OperandType::TENSOR_FLOAT32:
+ case OperandType::TENSOR_INT32:
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void mutateOperandRankTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+ const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
+ " has rank of " + std::to_string(invalidRank);
+ validate(device, message, model, [operand, invalidRank](Model* model) {
+ model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ });
+ }
+}
+
+///////////////////////// VALIDATE OPERAND SCALE /////////////////////////
+
+static float getInvalidScale(OperandType type) {
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ case OperandType::TENSOR_FLOAT32:
+ return 1.0f;
+ case OperandType::TENSOR_INT32:
+ return -1.0f;
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ return 0.0f;
+ default:
+ return 0.0f;
+ }
+}
+
+static void mutateOperandScaleTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const float invalidScale = getInvalidScale(model.operands[operand].type);
+ const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
+ " has scale of " + std::to_string(invalidScale);
+ validate(device, message, model, [operand, invalidScale](Model* model) {
+ model->operands[operand].scale = invalidScale;
+ });
+ }
+}
+
+///////////////////////// VALIDATE OPERAND ZERO POINT /////////////////////////
+
+static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ case OperandType::TENSOR_FLOAT32:
+ case OperandType::TENSOR_INT32:
+ return {1};
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ return {-1, 256};
+ default:
+ return {};
+ }
+}
+
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const std::vector<int32_t> invalidZeroPoints =
+ getInvalidZeroPoints(model.operands[operand].type);
+ for (int32_t invalidZeroPoint : invalidZeroPoints) {
+ const std::string message = "mutateOperandZeroPointTest: operand " +
+ std::to_string(operand) + " has zero point of " +
+ std::to_string(invalidZeroPoint);
+ validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
+ model->operands[operand].zeroPoint = invalidZeroPoint;
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE EXTRA ??? /////////////////////////
+
+// TODO: Operand::lifetime
+// TODO: Operand::location
+
+///////////////////////// VALIDATE OPERATION OPERAND TYPE /////////////////////////
+
+static void mutateOperand(Operand* operand, OperandType type) {
+ Operand newOperand = *operand;
+ newOperand.type = type;
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ newOperand.dimensions = hidl_vec<uint32_t>();
+ newOperand.scale = 0.0f;
+ newOperand.zeroPoint = 0;
+ break;
+ case OperandType::TENSOR_FLOAT32:
+ newOperand.dimensions =
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ newOperand.scale = 0.0f;
+ newOperand.zeroPoint = 0;
+ break;
+ case OperandType::TENSOR_INT32:
+ newOperand.dimensions =
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ newOperand.zeroPoint = 0;
+ break;
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ newOperand.dimensions =
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
+ break;
+ case OperandType::OEM:
+ case OperandType::TENSOR_OEM_BYTE:
+ default:
+ break;
+ }
+ *operand = newOperand;
+}
+
+static bool mutateOperationOperandTypeSkip(size_t operand, const V1_0::Model& model) {
+ // LSH_PROJECTION's second argument is allowed to have any type. This is the
+ // only operation that currently has a type that can be anything independent
+ // from any other type. Changing the operand type to any other type will
+ // result in a valid model for LSH_PROJECTION. If this is the case, skip the
+ // test.
+ for (const Operation& operation : model.operations) {
+ if (operation.type == OperationType::LSH_PROJECTION && operand == operation.inputs[1]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ if (mutateOperationOperandTypeSkip(operand, model)) {
+ continue;
+ }
+ for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
+ // Do not test OEM types
+ if (invalidOperandType == model.operands[operand].type ||
+ invalidOperandType == OperandType::OEM ||
+ invalidOperandType == OperandType::TENSOR_OEM_BYTE) {
+ continue;
+ }
+ const std::string message = "mutateOperationOperandTypeTest: operand " +
+ std::to_string(operand) + " set to type " +
+ toString(invalidOperandType);
+ validate(device, message, model, [operand, invalidOperandType](Model* model) {
+ mutateOperand(&model->operands[operand], invalidOperandType);
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
+
+static const int32_t invalidOperationTypes[] = {
+ static_cast<int32_t>(OperationType::ADD) - 1, // lower bound fundamental
+ static_cast<int32_t>(OperationType::TANH) + 1, // upper bound fundamental
+ static_cast<int32_t>(OperationType::OEM_OPERATION) - 1, // lower bound OEM
+ static_cast<int32_t>(OperationType::OEM_OPERATION) + 1, // upper bound OEM
+};
+
+static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (int32_t invalidOperationType : invalidOperationTypes) {
+ const std::string message = "mutateOperationTypeTest: operation " +
+ std::to_string(operation) + " set to value " +
+ std::to_string(invalidOperationType);
+ validate(device, message, model, [operation, invalidOperationType](Model* model) {
+ model->operations[operation].type =
+ static_cast<OperationType>(invalidOperationType);
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device,
+ const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.operands.size();
+ for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ const std::string message = "mutateOperationInputOperandIndexTest: operation " +
+ std::to_string(operation) + " input " +
+ std::to_string(input);
+ validate(device, message, model, [operation, input, invalidOperand](Model* model) {
+ model->operations[operation].inputs[input] = invalidOperand;
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device,
+ const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.operands.size();
+ for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
+ std::to_string(operation) + " output " +
+ std::to_string(output);
+ validate(device, message, model, [operation, output, invalidOperand](Model* model) {
+ model->operations[operation].outputs[output] = invalidOperand;
+ });
+ }
+ }
+}
+
+///////////////////////// REMOVE OPERAND FROM EVERYTHING /////////////////////////
+
+static void removeValueAndDecrementGreaterValues(hidl_vec<uint32_t>* vec, uint32_t value) {
+ if (vec) {
+ // remove elements matching "value"
+ auto last = std::remove(vec->begin(), vec->end(), value);
+ vec->resize(std::distance(vec->begin(), last));
+
+ // decrement elements exceeding "value"
+ std::transform(vec->begin(), vec->end(), vec->begin(),
+ [value](uint32_t v) { return v > value ? v-- : v; });
+ }
+}
+
+static void removeOperand(Model* model, uint32_t index) {
+ hidl_vec_removeAt(&model->operands, index);
+ for (Operation& operation : model->operations) {
+ removeValueAndDecrementGreaterValues(&operation.inputs, index);
+ removeValueAndDecrementGreaterValues(&operation.outputs, index);
+ }
+ removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+}
+
+static void removeOperandTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const std::string message = "removeOperandTest: operand " + std::to_string(operand);
+ validate(device, message, model,
+ [operand](Model* model) { removeOperand(model, operand); });
+ }
+}
+
+///////////////////////// REMOVE OPERATION /////////////////////////
+
+static void removeOperation(Model* model, uint32_t index) {
+ for (uint32_t operand : model->operations[index].inputs) {
+ model->operands[operand].numberOfConsumers--;
+ }
+ hidl_vec_removeAt(&model->operations, index);
+}
+
+static void removeOperationTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const std::string message = "removeOperationTest: operation " + std::to_string(operation);
+ validate(device, message, model,
+ [operation](Model* model) { removeOperation(model, operation); });
+ }
+}
+
+///////////////////////// REMOVE OPERATION INPUT /////////////////////////
+
+static void removeOperationInputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ const V1_0::Operation& op = model.operations[operation];
+ // CONCATENATION has at least 2 inputs, with the last element being
+ // INT32. Skip this test if removing one of CONCATENATION's
+ // inputs still produces a valid model.
+ if (op.type == V1_0::OperationType::CONCATENATION && op.inputs.size() > 2 &&
+ input != op.inputs.size() - 1) {
+ continue;
+ }
+ const std::string message = "removeOperationInputTest: operation " +
+ std::to_string(operation) + ", input " +
+ std::to_string(input);
+ validate(device, message, model, [operation, input](Model* model) {
+ uint32_t operand = model->operations[operation].inputs[input];
+ model->operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ });
+ }
+ }
+}
+
+///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
+
+static void removeOperationOutputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ const std::string message = "removeOperationOutputTest: operation " +
+ std::to_string(operation) + ", output " +
+ std::to_string(output);
+ validate(device, message, model, [operation, output](Model* model) {
+ hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ });
+ }
+ }
+}
+
+///////////////////////// MODEL VALIDATION /////////////////////////
+
+// TODO: remove model input
+// TODO: remove model output
+// TODO: add unused operation
+
+///////////////////////// ADD OPERATION INPUT /////////////////////////
+
+static void addOperationInputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
+ validate(device, message, model, [operation](Model* model) {
+ uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
+ hidl_vec_push_back(&model->operations[operation].inputs, index);
+ hidl_vec_push_back(&model->inputIndexes, index);
+ });
+ }
+}
+
+///////////////////////// ADD OPERATION OUTPUT /////////////////////////
+
+static void addOperationOutputTest(const sp<IDevice>& device, const V1_0::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const std::string message =
+ "addOperationOutputTest: operation " + std::to_string(operation);
+ validate(device, message, model, [operation](Model* model) {
+ uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
+ hidl_vec_push_back(&model->operations[operation].outputs, index);
+ hidl_vec_push_back(&model->outputIndexes, index);
+ });
+ }
+}
+
+////////////////////////// ENTRY POINT //////////////////////////////
+
+void ValidationTest::validateModel(const V1_0::Model& model) {
+ mutateOperandTypeTest(device, model);
+ mutateOperandRankTest(device, model);
+ mutateOperandScaleTest(device, model);
+ mutateOperandZeroPointTest(device, model);
+ mutateOperationOperandTypeTest(device, model);
+ mutateOperationTypeTest(device, model);
+ mutateOperationInputOperandIndexTest(device, model);
+ mutateOperationOutputOperandIndexTest(device, model);
+ removeOperandTest(device, model);
+ removeOperationTest(device, model);
+ removeOperationInputTest(device, model);
+ removeOperationOutputTest(device, model);
+ addOperationInputTest(device, model);
+ addOperationOutputTest(device, model);
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
+using test_helper::MixedTyped;
+using test_helper::MixedTypedExampleType;
+using test_helper::for_all;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void createPreparedModel(const sp<IDevice>& device, const V1_0::Model& model,
+ sp<IPreparedModel>* preparedModel) {
+ ASSERT_NE(nullptr, preparedModel);
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ Return<void> supportedOpsLaunchStatus = device->getSupportedOperations(
+ model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel =
+ std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+
+ // launch prepare model
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ *preparedModel = preparedModelCallback->getPreparedModel();
+
+ // The getSupportedOperations call returns a list of operations that are
+ // guaranteed not to fail if prepareModel is called, and
+ // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+ // If a driver has any doubt that it can prepare an operation, it must
+ // return false. So here, if a driver isn't sure if it can support an
+ // operation, but reports that it successfully prepared the model, the test
+ // can continue.
+ if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+ ASSERT_EQ(nullptr, preparedModel->get());
+ LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
+ "prepare model that it does not support.";
+ std::cout << "[ ] Unable to test Request validation because vendor service "
+ "cannot prepare model that it does not support."
+ << std::endl;
+ return;
+ }
+ ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ ASSERT_NE(nullptr, preparedModel->get());
+}
+
+// Primary validation function. This function will take a valid request, apply a
+// mutation to it to invalidate the request, then pass it to interface calls
+// that use the request. Note that the request here is passed by value, and any
+// mutation to the request does not leave this function.
+static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
+ Request request, const std::function<void(Request*)>& mutation) {
+ mutation(&request);
+ SCOPED_TRACE(message + " [execute]");
+
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ ASSERT_NE(nullptr, executionCallback.get());
+ Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
+ ASSERT_TRUE(executeLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
+
+ executionCallback->wait();
+ ErrorStatus executionReturnStatus = executionCallback->getStatus();
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+ if (vec) {
+ std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+ vec->resize(vec->size() - 1);
+ }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+ // assume vec is valid
+ const uint32_t index = vec->size();
+ vec->resize(index + 1);
+ (*vec)[index] = value;
+ return index;
+}
+
+///////////////////////// REMOVE INPUT ////////////////////////////////////
+
+static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ for (size_t input = 0; input < request.inputs.size(); ++input) {
+ const std::string message = "removeInput: removed input " + std::to_string(input);
+ validate(preparedModel, message, request,
+ [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); });
+ }
+}
+
+///////////////////////// REMOVE OUTPUT ////////////////////////////////////
+
+static void removeOutputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ for (size_t output = 0; output < request.outputs.size(); ++output) {
+ const std::string message = "removeOutput: removed Output " + std::to_string(output);
+ validate(preparedModel, message, request,
+ [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); });
+ }
+}
+
+///////////////////////////// ENTRY POINT //////////////////////////////////
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+ const uint32_t INPUT = 0;
+ const uint32_t OUTPUT = 1;
+
+ std::vector<Request> requests;
+
+ for (auto& example : examples) {
+ const MixedTyped& inputs = example.first;
+ const MixedTyped& outputs = example.second;
+
+ std::vector<RequestArgument> inputs_info, outputs_info;
+ uint32_t inputSize = 0, outputSize = 0;
+
+ // This function only partially specifies the metadata (vector of RequestArguments).
+ // The contents are copied over below.
+ for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
+ if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ RequestArgument arg_empty = {
+ .hasNoValue = true,
+ };
+ inputs_info[index] = s ? arg : arg_empty;
+ inputSize += s;
+ });
+ // Compute offset for inputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : inputs_info) {
+ if (!i.hasNoValue) i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+
+ // Go through all outputs, initialize RequestArgument descriptors
+ for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
+ if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ outputs_info[index] = arg;
+ outputSize += s;
+ });
+ // Compute offset for outputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : outputs_info) {
+ i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+ std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+ nn::allocateSharedMemory(outputSize)};
+ if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
+ return {};
+ }
+
+ // map pool
+ sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+ if (inputMemory == nullptr) {
+ return {};
+ }
+ char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
+ if (inputPtr == nullptr) {
+ return {};
+ }
+
+ // initialize pool
+ inputMemory->update();
+ for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
+ char* begin = (char*)p;
+ char* end = begin + s;
+ // TODO: handle more than one input
+ std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
+ });
+ inputMemory->commit();
+
+ requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
+ }
+
+ return requests;
+}
+
+void ValidationTest::validateRequests(const V1_0::Model& model,
+ const std::vector<Request>& requests) {
+ // create IPreparedModel
+ sp<IPreparedModel> preparedModel;
+ ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
+ if (preparedModel == nullptr) {
+ return;
+ }
+
+ // validate each request
+ for (const Request& request : requests) {
+ removeInputTest(preparedModel, request);
+ removeOutputTest(preparedModel, request);
+ }
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/ValidationTests.cpp b/neuralnetworks/1.0/vts/functional/ValidationTests.cpp
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "Models.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_0 {
+namespace vts {
+namespace functional {
+
+// forward declarations
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// generate validation tests
+#define VTS_CURRENT_TEST_CASE(TestName) \
+ TEST_F(ValidationTest, TestName) { \
+ const Model model = TestName::createTestModel(); \
+ const std::vector<Request> requests = createRequests(TestName::examples); \
+ validateModel(model); \
+ validateRequests(model, requests); \
+ }
+
+FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
+
+#undef VTS_CURRENT_TEST_CASE
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_0
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
similarity index 64%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index b14fb2c4c83c47812a9df79b8c02292913e81f96..1ff3b6680858a153cfdd17484a338b0ded7859cc 100644 (file)
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.cpp
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index b14fb2c4c83c47812a9df79b8c02292913e81f96..1ff3b6680858a153cfdd17484a338b0ded7859cc 100644 (file)
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworksV1_0.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-
-using ::android::hardware::hidl_memory;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
+#include "VtsHalNeuralnetworks.h"
namespace android {
namespace hardware {
namespace vts {
namespace functional {
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size) {
- return nn::allocateSharedMemory(size);
-}
-
// A class for test environment setup
NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
}
void NeuralnetworksHidlEnvironment::registerTestServices() {
- registerTestService<V1_0::IDevice>();
+ registerTestService<IDevice>();
}
// The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
+
NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
void NeuralnetworksHidlTest::SetUp() {
- device = ::testing::VtsHalHidlTargetTestBase::getService<V1_0::IDevice>(
+ ::testing::VtsHalHidlTargetTestBase::SetUp();
+ device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
NeuralnetworksHidlEnvironment::getInstance());
ASSERT_NE(nullptr, device.get());
}
-void NeuralnetworksHidlTest::TearDown() {}
+void NeuralnetworksHidlTest::TearDown() {
+ device = nullptr;
+ ::testing::VtsHalHidlTargetTestBase::TearDown();
+}
} // namespace functional
} // namespace vts
+
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
+ return os << toString(errorStatus);
+}
+
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
+ return os << toString(deviceStatus);
+}
+
} // namespace V1_0
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
+
+using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
+ ::testing::InitGoogleTest(&argc, argv);
+ NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
+
+ int status = RUN_ALL_TESTS();
+ return status;
+}
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
similarity index 60%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index fbb16074784ea690ada0ffff5273011af4616c90..e79129b09f51e06899324407eab782f500fbc856 100644 (file)
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0.h
rename to neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index fbb16074784ea690ada0ffff5273011af4616c90..e79129b09f51e06899324407eab782f500fbc856 100644 (file)
#define VTS_HAL_NEURALNETWORKS_V1_0_TARGET_TESTS_H
#include <android/hardware/neuralnetworks/1.0/IDevice.h>
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
+
+#include <android-base/macros.h>
#include <gtest/gtest.h>
-#include <string>
+#include <iostream>
+#include <vector>
namespace android {
namespace hardware {
namespace vts {
namespace functional {
-hidl_memory allocateSharedMemory(int64_t size);
-
// A class for test environment setup
class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
NeuralnetworksHidlEnvironment();
- NeuralnetworksHidlEnvironment(const NeuralnetworksHidlEnvironment&) = delete;
- NeuralnetworksHidlEnvironment(NeuralnetworksHidlEnvironment&&) = delete;
- NeuralnetworksHidlEnvironment& operator=(const NeuralnetworksHidlEnvironment&) = delete;
- NeuralnetworksHidlEnvironment& operator=(NeuralnetworksHidlEnvironment&&) = delete;
+ ~NeuralnetworksHidlEnvironment() override;
public:
- ~NeuralnetworksHidlEnvironment() override;
static NeuralnetworksHidlEnvironment* getInstance();
void registerTestServices() override;
};
// The main test class for NEURALNETWORKS HIDL HAL.
class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
+
public:
+ NeuralnetworksHidlTest();
~NeuralnetworksHidlTest() override;
void SetUp() override;
void TearDown() override;
- sp<V1_0::IDevice> device;
+ protected:
+ sp<IDevice> device;
};
+
+// Tag for the validation tests
+class ValidationTest : public NeuralnetworksHidlTest {
+ protected:
+ void validateModel(const Model& model);
+ void validateRequests(const Model& model, const std::vector<Request>& request);
+};
+
+// Tag for the generated tests
+class GeneratedTest : public NeuralnetworksHidlTest {};
+
} // namespace functional
} // namespace vts
// pretty-print values for error messages
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- V1_0::ErrorStatus errorStatus) {
- return os << toString(errorStatus);
-}
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- V1_0::DeviceStatus deviceStatus) {
- return os << toString(deviceStatus);
-}
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
} // namespace V1_0
} // namespace neuralnetworks
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0BasicTest.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2018 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_hidl_hal_test"
-
-#include "VtsHalNeuralnetworksV1_0.h"
-
-#include "Callbacks.h"
-#include "Models.h"
-#include "TestHarness.h"
-
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::OperationType;
-using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace vts {
-namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-
-static void doPrepareModelShortcut(const sp<IDevice>& device, sp<IPreparedModel>* preparedModel) {
- ASSERT_NE(nullptr, preparedModel);
- Model model = createValidTestModel_1_0();
-
- // see if service can handle model
- bool fullySupportsModel = false;
- Return<void> supportedOpsLaunchStatus = device->getSupportedOperations(
- model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
- ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_NE(0ul, supported.size());
- fullySupportsModel =
- std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
- });
- ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
-
- // launch prepare model
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- // retrieve prepared model
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- *preparedModel = preparedModelCallback->getPreparedModel();
-
- // The getSupportedOperations call returns a list of operations that are
- // guaranteed not to fail if prepareModel is called, and
- // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
- // If a driver has any doubt that it can prepare an operation, it must
- // return false. So here, if a driver isn't sure if it can support an
- // operation, but reports that it successfully prepared the model, the test
- // can continue.
- if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
- ASSERT_EQ(nullptr, preparedModel->get());
- 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;
- return;
- }
- ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
- ASSERT_NE(nullptr, preparedModel->get());
-}
-
-// create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
-
-// status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
- Return<DeviceStatus> status = device->getStatus();
- ASSERT_TRUE(status.isOk());
- EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
-}
-
-// initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
- Return<void> ret =
- device->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
- EXPECT_EQ(ErrorStatus::NONE, status);
- EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
- EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
- EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
- EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations positive test
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
- Model model = createValidTestModel_1_0();
- Return<void> ret = device->getSupportedOperations(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- EXPECT_EQ(ErrorStatus::NONE, status);
- EXPECT_EQ(model.operations.size(), supported.size());
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 1
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
- Model model = createInvalidTestModel1_1_0();
- Return<void> ret = device->getSupportedOperations(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
- (void)supported;
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 2
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
- Model model = createInvalidTestModel2_1_0();
- Return<void> ret = device->getSupportedOperations(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
- (void)supported;
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// prepare simple model positive test
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
- sp<IPreparedModel> preparedModel;
- doPrepareModelShortcut(device, &preparedModel);
-}
-
-// prepare simple model negative test 1
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
- Model model = createInvalidTestModel1_1_0();
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
- sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
- EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// prepare simple model negative test 2
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
- Model model = createInvalidTestModel2_1_0();
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
- sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
- EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// execute simple graph positive test
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphPositiveTest) {
- std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
- std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
- const uint32_t OUTPUT = 1;
-
- sp<IPreparedModel> preparedModel;
- ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
- if (preparedModel == nullptr) {
- return;
- }
- Request request = createValidTestRequest();
-
- auto postWork = [&] {
- sp<IMemory> outputMemory = mapMemory(request.pools[OUTPUT]);
- if (outputMemory == nullptr) {
- return false;
- }
- float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
- if (outputPtr == nullptr) {
- return false;
- }
- outputMemory->read();
- std::copy(outputPtr, outputPtr + outputData.size(), outputData.begin());
- outputMemory->commit();
- return true;
- };
-
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- executionCallback->on_finish(postWork);
- Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executeLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executeLaunchStatus));
-
- executionCallback->wait();
- ErrorStatus executionReturnStatus = executionCallback->getStatus();
- EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus);
- EXPECT_EQ(expectedData, outputData);
-}
-
-// execute simple graph negative test 1
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
- sp<IPreparedModel> preparedModel;
- ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
- if (preparedModel == nullptr) {
- return;
- }
- Request request = createInvalidTestRequest1();
-
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executeLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
- executionCallback->wait();
- ErrorStatus executionReturnStatus = executionCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-// execute simple graph negative test 2
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
- sp<IPreparedModel> preparedModel;
- ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
- if (preparedModel == nullptr) {
- return;
- }
- Request request = createInvalidTestRequest2();
-
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executeLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
- executionCallback->wait();
- ErrorStatus executionReturnStatus = executionCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_0
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
-
-using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
- ::testing::InitGoogleTest(&argc, argv);
- NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
- int status = RUN_ALL_TESTS();
- return status;
-}
index ca225554d506d9d013cb600d4c4740bff9c8f95b..1335bde193f6fa67cc542cfb11d8914ad6f3a635 100644 (file)
/**
* Gets the supported operations in a model.
*
- * getSupportedSubgraph indicates which operations of a model are fully
+ * getSupportedOperations indicates which operations of a model are fully
* supported by the vendor driver. If an operation may not be supported for
* any reason, getSupportedOperations must return false for that operation.
*
* Multiple threads can 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 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
* - INVALID_ARGUMENT if one of the input arguments is
* invalid
*/
- prepareModel_1_1(Model model, IPreparedModelCallback callback)
+ prepareModel_1_1(Model model, ExecutionPreference preference,
+ IPreparedModelCallback callback)
generates (ErrorStatus status);
};
index 1d470d636fbdeaf517e4a1ce0f8a0e64c974bf8e..e4c656db449c43008d11fda5d556338160bbafd4 100644 (file)
*/
enum OperationType : @1.0::OperationType {
/**
- * BatchToSpace for N-D tensors.
+ * BatchToSpace for N-dimensional tensors.
+ *
+ * This operation reshapes the batch dimension (dimension 0) into M + 1
+ * dimensions of shape block_shape + [batch], interleaves these blocks back
+ * into the grid defined by the spatial dimensions [1, ..., M], to obtain a
+ * result with the same rank as the input.
*
- * This operation reshapes the "batch" dimension 0 into M + 1 dimensions of shape
- * block_shape + [batch], interleaves these blocks back into the grid defined by the
- * spatial dimensions [1, ..., M], to obtain a result with the same rank as the input.
- * The spatial dimensions of this intermediate result are then optionally cropped
- * according to the amount to crop to produce the output.
* This is the reverse of SpaceToBatch.
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
- * Supported tensor rank: up to 4
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: 4
*
* Inputs:
- * 0: An n-D tensor, specifying the input.
- * 1: A 1-D Tensor of type TENSOR_INT32, the block sizes for each spatial dimension of the
- * input tensor. All values must be >= 1.
- * 2: A 1-D Tensor of type TENSOR_INT32, the amount to crop for each spatial diemension of the
- * input tensor. All values must be >= 0.
+ * * 0: An n-D tensor, specifying the tensor to be reshaped
+ * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block
+ * sizes for each spatial dimension of the input tensor. All values
+ * must be >= 1.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
BATCH_TO_SPACE_ND = 29,
/**
- * Divides the second tensor from the first tensor, element-wise.
+ * Element-wise division of two tensors.
*
- * Takes two input tensors of identical OperandType and compatible dimensions. The output
- * is the result of dividing the first input tensor by the second, optionally
- * modified by an activation function.
+ * Takes two input tensors of identical {@link OperandType} and compatible
+ * dimensions. The output is the result of dividing the first input tensor
+ * by the second, optionally modified by an activation function.
*
* Two dimensions are compatible when:
* 1. they are equal, or
* 2. one of them is 1
*
- * The size of the output is the maximum size along each dimension of the input operands.
- * It starts with the trailing dimensions, and works its way forward.
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its way
+ * forward.
*
* Example:
* input1.dimension = {4, 1, 2}
* input2.dimension = {5, 4, 3, 1}
* output.dimension = {5, 4, 3, 2}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: An n-D tensor, specifying the first input.
- * 1: A tensor of the same type, and compatible dimensions as input0.
- * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
+ * * 0: An n-D tensor, specifying the first input.
+ * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
DIV = 30,
/**
* Computes the mean of elements across dimensions of a tensor.
*
- * Reduces input tensor along the dimensions given in axis. Unless keep_dims is true,
- * the rank of the tensor is reduced by 1 for each entry in axis. If keep_dims is
- * true, the reduced dimensions are retained with length 1.
+ * Reduces the input tensor along the given dimensions to reduce. Unless
+ * keep_dims is true, the rank of the tensor is reduced by 1 for each entry
+ * in axis. If keep_dims is true, the reduced dimensions are retained with
+ * length 1.
+ *
+ * If dimensions to reduce have no entries, all dimensions are reduced, and
+ * a tensor with a single element is returned.
*
- * If axis has no entries, all dimensions are reduced, and a tensor with a single
- * element is returned.
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: A tensor, specifying the input.
- * 1: A 1-D Tensor of type TENSOR_INT32. The dimensions to reduce. If None (the default),
- * reduces all dimensions. Must be in the range [-rank(input_tensor), rank(input_tensor)).
- * 2: An INT32 value, keep_dims. If positive, retains reduced dimensions with length 1.
+ * * 0: A tensor, specifying the input.
+ * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}. The dimensions
+ * to reduce. If None (the default), reduces all dimensions. Must be in
+ * the range [-rank(input_tensor), rank(input_tensor)).
+ * * 2: An {@link OperandType::INT32} scalar, keep_dims. If positive,
+ * retains reduced dimensions with length 1.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
MEAN = 31,
*
* This operation pads a tensor according to the specified paddings.
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: An n-D tensor, specifying the input.
- * 1: A 2-D Tensor of type TENSOR_INT32. The paddings, before and after for each spatial dimension
- * of the input tensor.
+ * * 0: An n-D tensor, specifying the tensor to be padded.
+ * * 1: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+ * for each spatial dimension of the input tensor. The shape of the
+ * tensor must be {rank(input0), 2}.
+ * padding[i, 0] specifies the number of element to be padded in the
+ * front of dimension i.
+ * padding[i, 1] specifies the number of element to be padded after the
+ * end of dimension i.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
PAD = 32,
/**
- * SpaceToBatch for N-D tensors.
+ * SpaceToBatch for N-Dimensional tensors.
*
- * This operation divides "spatial" dimensions [1, ..., M] of the input into a grid of blocks
- * of shape block_shape, and interleaves these blocks with the "batch" dimension (0) such that
- * in the output, the spatial dimensions [1, ..., M] correspond to the position within the grid,
- * and the batch dimension combines both the position within a spatial block and the original
- * batch position. Prior to division into blocks, the spatial dimensions of the input are
- * optionally zero padded according to paddings.
+ * This operation divides "spatial" dimensions [1, ..., M] of the input into
+ * a grid of blocks of shape block_shape, and interleaves these blocks with
+ * the "batch" dimension (0) such that in the output, the spatial dimensions
+ * [1, ..., M] correspond to the position within the grid, and the batch
+ * dimension combines both the position within a spatial block and the
+ * original batch position. Prior to division into blocks, the spatial
+ * dimensions of the input are optionally zero padded according to paddings.
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
- * Supported tensor rank: up to 4
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+ *
+ * Supported tensor rank: 4
*
* Inputs:
- * 0: An n-D tensor, specifying the input.
- * 1: A 1-D Tensor of type TENSOR_INT32, the block sizes for each spatial dimension of the
- * input tensor. All values must be >= 1.
- * 2: A 2-D Tensor of type TENSOR_INT32, the paddings for each spatial diemension of the
- * input tensor. All values must be >= 0.
+ * * 0: An n-D tensor, specifying the input.
+ * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the block
+ * sizes for each spatial dimension of the input tensor. All values
+ * must be >= 1.
+ * * 2: A 2-D Tensor of {@link OperandType::TENSOR_INT32}, the paddings
+ * for each spatial dimension of the input tensor. All values must be
+ * >= 0. The shape of the tensor must be {rank(input0), 2}.
+ * padding[i, 0] specifies the number of element to be padded in the
+ * front of dimension i.
+ * padding[i, 1] specifies the number of element to be padded after the
+ * end of dimension i.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
SPACE_TO_BATCH_ND = 33,
/**
* Removes dimensions of size 1 from the shape of a tensor.
*
- * Given a tensor input, this operation returns a tensor of the same type with all
- * dimensions of size 1 removed. If you don't want to remove all size 1 dimensions,
- * you can remove specific size 1 dimensions by specifying axis.
+ * Given a tensor input, this operation returns a tensor of the same
+ * {@link OperandType} with all dimensions of size 1 removed. If you don't
+ * want to remove all size 1 dimensions, you can remove specific size 1
+ * dimensions by specifying the axes (input1).
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: An n-D tensor, specifying the input.
- * 1: An 1-D Tensor of type TENSOR_INT32. The dimensions to squeeze. If None (the default),
- * squeezes all dimensions. If specified, only squeezes the dimensions listed. The dimension
- * index starts at 0. It is an error to squeeze a dimension that is not 1.
+ * * 0: An n-D tensor, the tensor to be squeezed.
+ * * 1: An optional 1-D tensor of {@link OperandType::TENSOR_INT32}. The
+ * dimensions to squeeze. If specified only squeezes the dimensions
+ * listed. Otherwise, squeezes all dimensions. The dimension index
+ * starts at 0. An error must be reported if squeezing a dimension that
+ * is not 1.
*
* Outputs:
- * 0: A tensor of the same type as input0. Contains the same data as input, but has one or more
- * dimensions of size 1 removed.
+ * * 0: A tensor of the same {@link OperandType} as input0. Contains the
+ * same data as input, but has one or more dimensions of size 1
+ * removed.
*/
SQUEEZE = 34,
/**
* Extracts a strided slice of a tensor.
*
- * This op extracts a slice of size (end-begin)/stride from the given input tensor.
- * Starting at the location specified by begin the slice continues by adding
- * stride to the index until all dimensions are not less than end. Note that a stride can
- * be negative, which causes a reverse slice.
+ * Roughly speaking, this op extracts a slice of size (end - begin) / stride
+ * from the given input tensor. Starting at the location specified by begin
+ * the slice continues by adding stride to the index until all dimensions
+ * are not less than end. Note that a stride can be negative, which causes a
+ * reverse slice.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: An n-D tensor, specifying the input.
- * 1: A 1-D Tensor of type TENSOR_INT32, the starts of the dimensions of the input
- * tensor to be sliced.
- * 2: A 1-D Tensor of type TENSOR_INT32, the ends of the dimensions of the input
- * tensor to be sliced.
- * 3: A 1-D Tensor of type TENSOR_INT32, the strides of the dimensions of the input
- * tensor to be sliced.
+ * * 0: An n-D tensor, specifying the tensor to be sliced.
+ * * 1: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the starts of
+ * the dimensions of the input tensor to be sliced. The length must be
+ * of rank(input0).
+ * * 2: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the ends of
+ * the dimensions of the input tensor to be sliced. The length must be
+ * of rank(input0).
+ * * 3: A 1-D Tensor of {@link OperandType::TENSOR_INT32}, the strides of
+ * the dimensions of the input tensor to be sliced. The length must be
+ * of rank(input0).
+ * * 4: An {@link OperandType::INT32} scalar, begin_mask. If the ith bit
+ * of begin_mask is set, begin[i] is ignored and the fullest possible
+ * range in that dimension is used instead.
+ * * 5: An {@link OperandType::INT32} scalar, end_mask. If the ith bit of
+ * end_mask is set, end[i] is ignored and the fullest possible range in
+ * that dimension is used instead.
+ * * 6: An {@link OperandType::INT32} scalar, shrink_axis_mask. An int32
+ * mask. If the ith bit of shrink_axis_mask is set, it implies that the
+ * ith specification shrinks the dimensionality by 1. A slice of size 1
+ * starting from begin[i] in the dimension must be preserved.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
STRIDED_SLICE = 35,
/**
- * Subtracts the second tensor from the first tensor, element-wise.
+ * Element-wise subtraction of two tensors.
*
- * Takes two input tensors of identical type and compatible dimensions. The output
- * is the result of subtracting the second input tensor from the first one, optionally
- * modified by an activation function.
+ * Takes two input tensors of identical {@link OperandType} and compatible
+ * dimensions. The output is the result of subtracting the second input
+ * tensor from the first one, optionally modified by an activation function.
*
* Two dimensions are compatible when:
* 1. they are equal, or
* 2. one of them is 1
*
- * The size of the output is the maximum size along each dimension of the input operands.
- * It starts with the trailing dimensions, and works its way forward.
+ * The size of the output is the maximum size along each dimension of the
+ * input operands. It starts with the trailing dimensions, and works its way
+ * forward.
*
* Example:
* input1.dimension = {4, 1, 2}
* input2.dimension = {5, 4, 3, 1}
* output.dimension = {5, 4, 3, 2}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ *
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: An n-D tensor, specifying the first input.
- * 1: A tensor of the same type, and compatible dimensions as input0.
- * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
- * Specifies the activation to invoke on the result of each addition.
+ * * 0: An n-D tensor, specifying the first input.
+ * * 1: A tensor of the same {@link OperandType}, and compatible dimensions
+ * as input0.
+ * * 2: An {@link OperandType::INT32} scalar, and has to be one of the
+ * {@link FusedActivationFunc} values. Specifies the activation to
+ * invoke on the result.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
SUB = 36,
/**
- * Transposes the input tensor, permuting the dimensions according to the perm tensor.
+ * Transposes the input tensor, permuting the dimensions according to the
+ * perm tensor.
*
- * The returned tensor's dimension i must correspond to the input dimension perm[i].
- * If perm is not given, it is set to (n-1...0), where n is the rank of the input tensor.
- * Hence by default, this operation performs a regular matrix transpose on 2-D input Tensors.
+ * The returned tensor's dimension i corresponds to the input dimension
+ * perm[i]. If perm is not given, it is set to (n-1...0), where n is the
+ * rank of the input tensor. Hence by default, this operation performs a
+ * regular matrix transpose on 2-D input Tensors.
+ *
+ * Supported tensor {@link OperandType}:
+ * * {@link OperandType::TENSOR_FLOAT32}
+ * * {@link OperandType::TENSOR_QUANT8_ASYMM}
*
- * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
- * {@link OperandType::TENSOR_QUANT8_ASYMM}
* Supported tensor rank: up to 4
*
* Inputs:
- * 0: An n-D tensor, specifying the input.
- * 1: A 1-D Tensor of type TENSOR_INT32, the permutation of the dimensions of the input
- * tensor.
+ * * 0: An n-D tensor, specifying the tensor to be transposed.
+ * * 1: An optional 1-D Tensor of {@link OperandType::TENSOR_INT32},
+ * the permutation of the dimensions of the input tensor.
*
* Outputs:
- * 0: A tensor of the same type as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0.
*/
TRANSPOSE = 37,
};
*/
bool relaxComputationFloat32toFloat16;
};
+
+/**
+ * Execution preferences.
+ */
+enum ExecutionPreference : int32_t {
+ /**
+ * Prefer executing in a way that minimizes battery drain.
+ * This is desirable for compilations that will be executed often.
+ */
+ LOW_POWER = 0,
+ /**
+ * Prefer returning a single answer as fast as possible, even if this causes
+ * more power consumption.
+ */
+ FAST_SINGLE_ANSWER = 1,
+ /**
+ * Prefer maximizing the throughput of successive frames, for example when
+ * processing successive frames coming from the camera.
+ */
+ SUSTAINED_SPEED = 2,
+};
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 623b44103a0db686457358db9835d16144ce7a8b..f755c20be5a9bdd531909105f3c3a88a67e5e43a 100644 (file)
cc_test {
name: "VtsHalNeuralnetworksV1_1TargetTest",
srcs: [
- "VtsHalNeuralnetworksV1_1.cpp",
- "VtsHalNeuralnetworksV1_1BasicTest.cpp",
- "VtsHalNeuralnetworksV1_1GeneratedTest.cpp",
+ "BasicTests.cpp",
+ "GeneratedTests.cpp",
+ "ValidateModel.cpp",
+ "ValidateRequest.cpp",
+ "ValidationTests.cpp",
+ "VtsHalNeuralnetworks.cpp",
],
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
"libneuralnetworks_generated_test_harness_headers",
"libneuralnetworks_generated_tests",
],
+ // Bug: http://b/74200014 - Disable arm32 asan since it triggers internal
+ // error in ld.gold.
+ arch: {
+ arm: {
+ sanitize: {
+ never: true,
+ },
+ },
+ },
}
diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+// create device test
+TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+
+// status test
+TEST_F(NeuralnetworksHidlTest, StatusTest) {
+ Return<DeviceStatus> status = device->getStatus();
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
+}
+
+// initialization
+TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+ Return<void> ret =
+ device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
+ EXPECT_EQ(ErrorStatus::NONE, status);
+ EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
+ EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
+ EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
+ EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
+ EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime);
+ EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage);
+ });
+ EXPECT_TRUE(ret.isOk());
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
similarity index 57%
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp
rename to neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
index b99aef7fc00bd7b2a55de877a7e943f62eaab465..95c2b1aca05f653c57362e566e64bf902fc26d8a 100644 (file)
rename from neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworksV1_0GeneratedTest.cpp
rename to neuralnetworks/1.1/vts/functional/GeneratedTests.cpp
index b99aef7fc00bd7b2a55de877a7e943f62eaab465..95c2b1aca05f653c57362e566e64bf902fc26d8a 100644 (file)
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworksV1_0.h"
+#include "VtsHalNeuralnetworks.h"
#include "Callbacks.h"
#include "TestHarness.h"
+#include "Utils.h"
#include <android-base/logging.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
-using ::android::hardware::neuralnetworks::V1_0::IDevice;
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Model;
-using ::android::hardware::neuralnetworks::V1_0::OperationType;
-using ::android::hardware::neuralnetworks::V1_0::PerformanceInfo;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
namespace android {
namespace hardware {
namespace neuralnetworks {
namespace generated_tests {
-using ::generated_tests::MixedTypedExampleType;
-extern void Execute(sp<IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
- const std::vector<MixedTypedExampleType>&);
+using ::test_helper::MixedTypedExampleType;
+extern void Execute(const sp<V1_1::IDevice>&, std::function<V1_1::Model(void)>,
+ std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
} // namespace generated_tests
-namespace V1_0 {
+namespace V1_1 {
namespace vts {
namespace functional {
+
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
// Mixed-typed examples
typedef generated_tests::MixedTypedExampleType MixedTypedExample;
// in frameworks/ml/nn/runtime/tests/generated/
#include "all_generated_V1_0_vts_tests.cpp"
+#include "all_generated_V1_1_vts_tests.cpp"
} // namespace functional
} // namespace vts
-} // namespace V1_0
+} // namespace V1_1
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/Models.h b/neuralnetworks/1.1/vts/functional/Models.h
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2018 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 VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
+#define VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "TestHarness.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+using MixedTypedExample = test_helper::MixedTypedExampleType;
+
+#define FOR_EACH_TEST_MODEL(FN) \
+ FN(add) \
+ FN(add_broadcast_quant8) \
+ FN(add_quant8) \
+ FN(add_relaxed) \
+ FN(avg_pool_float_1) \
+ FN(avg_pool_float_1_relaxed) \
+ FN(avg_pool_float_2) \
+ FN(avg_pool_float_2_relaxed) \
+ FN(avg_pool_float_3) \
+ FN(avg_pool_float_3_relaxed) \
+ FN(avg_pool_float_4) \
+ FN(avg_pool_float_4_relaxed) \
+ FN(avg_pool_float_5) \
+ FN(avg_pool_quant8_1) \
+ FN(avg_pool_quant8_2) \
+ FN(avg_pool_quant8_3) \
+ FN(avg_pool_quant8_4) \
+ FN(avg_pool_quant8_5) \
+ FN(batch_to_space) \
+ FN(batch_to_space_float_1) \
+ FN(batch_to_space_quant8_1) \
+ FN(concat_float_1) \
+ FN(concat_float_1_relaxed) \
+ FN(concat_float_2) \
+ FN(concat_float_2_relaxed) \
+ FN(concat_float_3) \
+ FN(concat_float_3_relaxed) \
+ FN(concat_quant8_1) \
+ FN(concat_quant8_2) \
+ FN(concat_quant8_3) \
+ FN(conv_1_h3_w2_SAME) \
+ FN(conv_1_h3_w2_SAME_relaxed) \
+ FN(conv_1_h3_w2_VALID) \
+ FN(conv_1_h3_w2_VALID_relaxed) \
+ FN(conv_3_h3_w2_SAME) \
+ FN(conv_3_h3_w2_SAME_relaxed) \
+ FN(conv_3_h3_w2_VALID) \
+ FN(conv_3_h3_w2_VALID_relaxed) \
+ FN(conv_float) \
+ FN(conv_float_2) \
+ FN(conv_float_channels) \
+ FN(conv_float_channels_relaxed) \
+ FN(conv_float_channels_weights_as_inputs) \
+ FN(conv_float_channels_weights_as_inputs_relaxed) \
+ FN(conv_float_large) \
+ FN(conv_float_large_relaxed) \
+ FN(conv_float_large_weights_as_inputs) \
+ FN(conv_float_large_weights_as_inputs_relaxed) \
+ FN(conv_float_relaxed) \
+ FN(conv_float_weights_as_inputs) \
+ FN(conv_float_weights_as_inputs_relaxed) \
+ FN(conv_quant8) \
+ FN(conv_quant8_2) \
+ FN(conv_quant8_channels) \
+ FN(conv_quant8_channels_weights_as_inputs) \
+ FN(conv_quant8_large) \
+ FN(conv_quant8_large_weights_as_inputs) \
+ FN(conv_quant8_overflow) \
+ FN(conv_quant8_overflow_weights_as_inputs) \
+ FN(conv_quant8_weights_as_inputs) \
+ FN(depth_to_space_float_1) \
+ FN(depth_to_space_float_1_relaxed) \
+ FN(depth_to_space_float_2) \
+ FN(depth_to_space_float_2_relaxed) \
+ FN(depth_to_space_float_3) \
+ FN(depth_to_space_float_3_relaxed) \
+ FN(depth_to_space_quant8_1) \
+ FN(depth_to_space_quant8_2) \
+ FN(depthwise_conv) \
+ FN(depthwise_conv2d_float) \
+ FN(depthwise_conv2d_float_2) \
+ FN(depthwise_conv2d_float_large) \
+ FN(depthwise_conv2d_float_large_2) \
+ FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
+ FN(depthwise_conv2d_float_large_relaxed) \
+ FN(depthwise_conv2d_float_large_weights_as_inputs) \
+ FN(depthwise_conv2d_float_large_weights_as_inputs_relaxed) \
+ FN(depthwise_conv2d_float_weights_as_inputs) \
+ FN(depthwise_conv2d_quant8) \
+ FN(depthwise_conv2d_quant8_2) \
+ FN(depthwise_conv2d_quant8_large) \
+ FN(depthwise_conv2d_quant8_large_weights_as_inputs) \
+ FN(depthwise_conv2d_quant8_weights_as_inputs) \
+ FN(depthwise_conv_relaxed) \
+ FN(dequantize) \
+ FN(div) \
+ FN(embedding_lookup) \
+ FN(embedding_lookup_relaxed) \
+ FN(floor) \
+ FN(floor_relaxed) \
+ FN(fully_connected_float) \
+ FN(fully_connected_float_2) \
+ FN(fully_connected_float_large) \
+ FN(fully_connected_float_large_weights_as_inputs) \
+ FN(fully_connected_float_relaxed) \
+ FN(fully_connected_float_weights_as_inputs) \
+ FN(fully_connected_float_weights_as_inputs_relaxed) \
+ FN(fully_connected_quant8) \
+ FN(fully_connected_quant8_2) \
+ FN(fully_connected_quant8_large) \
+ FN(fully_connected_quant8_large_weights_as_inputs) \
+ FN(fully_connected_quant8_weights_as_inputs) \
+ FN(hashtable_lookup_float) \
+ FN(hashtable_lookup_float_relaxed) \
+ FN(hashtable_lookup_quant8) \
+ FN(l2_normalization) \
+ FN(l2_normalization_2) \
+ FN(l2_normalization_large) \
+ FN(l2_normalization_large_relaxed) \
+ FN(l2_normalization_relaxed) \
+ FN(l2_pool_float) \
+ FN(l2_pool_float_2) \
+ FN(l2_pool_float_large) \
+ FN(l2_pool_float_relaxed) \
+ FN(local_response_norm_float_1) \
+ FN(local_response_norm_float_1_relaxed) \
+ FN(local_response_norm_float_2) \
+ FN(local_response_norm_float_2_relaxed) \
+ FN(local_response_norm_float_3) \
+ FN(local_response_norm_float_3_relaxed) \
+ FN(local_response_norm_float_4) \
+ FN(local_response_norm_float_4_relaxed) \
+ FN(logistic_float_1) \
+ FN(logistic_float_1_relaxed) \
+ FN(logistic_float_2) \
+ FN(logistic_float_2_relaxed) \
+ FN(logistic_quant8_1) \
+ FN(logistic_quant8_2) \
+ FN(lsh_projection) \
+ FN(lsh_projection_2) \
+ FN(lsh_projection_2_relaxed) \
+ FN(lsh_projection_relaxed) \
+ FN(lsh_projection_weights_as_inputs) \
+ FN(lsh_projection_weights_as_inputs_relaxed) \
+ FN(lstm) \
+ FN(lstm2) \
+ FN(lstm2_relaxed) \
+ FN(lstm2_state) \
+ FN(lstm2_state2) \
+ FN(lstm2_state2_relaxed) \
+ FN(lstm2_state_relaxed) \
+ FN(lstm3) \
+ FN(lstm3_relaxed) \
+ FN(lstm3_state) \
+ FN(lstm3_state2) \
+ FN(lstm3_state2_relaxed) \
+ FN(lstm3_state3) \
+ FN(lstm3_state3_relaxed) \
+ FN(lstm3_state_relaxed) \
+ FN(lstm_relaxed) \
+ FN(lstm_state) \
+ FN(lstm_state2) \
+ FN(lstm_state2_relaxed) \
+ FN(lstm_state_relaxed) \
+ FN(max_pool_float_1) \
+ FN(max_pool_float_1_relaxed) \
+ FN(max_pool_float_2) \
+ FN(max_pool_float_2_relaxed) \
+ FN(max_pool_float_3) \
+ FN(max_pool_float_3_relaxed) \
+ FN(max_pool_float_4) \
+ FN(max_pool_quant8_1) \
+ FN(max_pool_quant8_2) \
+ FN(max_pool_quant8_3) \
+ FN(max_pool_quant8_4) \
+ FN(mean) \
+ FN(mean_float_1) \
+ FN(mean_float_2) \
+ FN(mean_quant8_1) \
+ FN(mean_quant8_2) \
+ FN(mobilenet_224_gender_basic_fixed) \
+ FN(mobilenet_224_gender_basic_fixed_relaxed) \
+ FN(mobilenet_quantized) \
+ FN(mul) \
+ FN(mul_broadcast_quant8) \
+ FN(mul_quant8) \
+ FN(mul_relaxed) \
+ FN(mul_relu) \
+ FN(mul_relu_relaxed) \
+ FN(pad) \
+ FN(pad_float_1) \
+ FN(relu1_float_1) \
+ FN(relu1_float_1_relaxed) \
+ FN(relu1_float_2) \
+ FN(relu1_float_2_relaxed) \
+ FN(relu1_quant8_1) \
+ FN(relu1_quant8_2) \
+ FN(relu6_float_1) \
+ FN(relu6_float_1_relaxed) \
+ FN(relu6_float_2) \
+ FN(relu6_float_2_relaxed) \
+ FN(relu6_quant8_1) \
+ FN(relu6_quant8_2) \
+ FN(relu_float_1) \
+ FN(relu_float_1_relaxed) \
+ FN(relu_float_2) \
+ FN(relu_quant8_1) \
+ FN(relu_quant8_2) \
+ FN(reshape) \
+ FN(reshape_quant8) \
+ FN(reshape_quant8_weights_as_inputs) \
+ FN(reshape_relaxed) \
+ FN(reshape_weights_as_inputs) \
+ FN(reshape_weights_as_inputs_relaxed) \
+ FN(resize_bilinear) \
+ FN(resize_bilinear_2) \
+ FN(resize_bilinear_relaxed) \
+ FN(rnn) \
+ FN(rnn_relaxed) \
+ FN(rnn_state) \
+ FN(rnn_state_relaxed) \
+ FN(softmax_float_1) \
+ FN(softmax_float_1_relaxed) \
+ FN(softmax_float_2) \
+ FN(softmax_float_2_relaxed) \
+ FN(softmax_quant8_1) \
+ FN(softmax_quant8_2) \
+ FN(space_to_batch) \
+ FN(space_to_batch_float_1) \
+ FN(space_to_batch_float_2) \
+ FN(space_to_batch_float_3) \
+ FN(space_to_batch_quant8_1) \
+ FN(space_to_batch_quant8_2) \
+ FN(space_to_batch_quant8_3) \
+ FN(space_to_depth_float_1) \
+ FN(space_to_depth_float_1_relaxed) \
+ FN(space_to_depth_float_2) \
+ FN(space_to_depth_float_2_relaxed) \
+ FN(space_to_depth_float_3) \
+ FN(space_to_depth_float_3_relaxed) \
+ FN(space_to_depth_quant8_1) \
+ FN(space_to_depth_quant8_2) \
+ FN(squeeze) \
+ FN(squeeze_float_1) \
+ FN(squeeze_quant8_1) \
+ FN(strided_slice) \
+ FN(strided_slice_float_1) \
+ FN(strided_slice_float_10) \
+ FN(strided_slice_float_2) \
+ FN(strided_slice_float_3) \
+ FN(strided_slice_float_4) \
+ FN(strided_slice_float_5) \
+ FN(strided_slice_float_6) \
+ FN(strided_slice_float_7) \
+ FN(strided_slice_float_8) \
+ FN(strided_slice_float_9) \
+ FN(strided_slice_qaunt8_10) \
+ FN(strided_slice_quant8_1) \
+ FN(strided_slice_quant8_2) \
+ FN(strided_slice_quant8_3) \
+ FN(strided_slice_quant8_4) \
+ FN(strided_slice_quant8_5) \
+ FN(strided_slice_quant8_6) \
+ FN(strided_slice_quant8_7) \
+ FN(strided_slice_quant8_8) \
+ FN(strided_slice_quant8_9) \
+ FN(sub) \
+ FN(svdf) \
+ FN(svdf2) \
+ FN(svdf2_relaxed) \
+ FN(svdf_relaxed) \
+ FN(svdf_state) \
+ FN(svdf_state_relaxed) \
+ FN(tanh) \
+ FN(tanh_relaxed) \
+ FN(transpose) \
+ FN(transpose_float_1) \
+ FN(transpose_quant8_1)
+
+#define FORWARD_DECLARE_GENERATED_OBJECTS(function) \
+ namespace function { \
+ extern std::vector<MixedTypedExample> examples; \
+ Model createTestModel(); \
+ }
+
+FOR_EACH_TEST_MODEL(FORWARD_DECLARE_GENERATED_OBJECTS)
+
+#undef FORWARD_DECLARE_GENERATED_OBJECTS
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+#endif // VTS_HAL_NEURALNETWORKS_V1_1_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+
+using V1_0::IPreparedModel;
+using V1_0::Operand;
+using V1_0::OperandLifeTime;
+using V1_0::OperandType;
+
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
+ const V1_1::Model& model) {
+ SCOPED_TRACE(message + " [getSupportedOperations_1_1]");
+
+ Return<void> ret =
+ device->getSupportedOperations_1_1(model, [&](ErrorStatus status, const hidl_vec<bool>&) {
+ EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
+ });
+ EXPECT_TRUE(ret.isOk());
+}
+
+static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
+ const V1_1::Model& model, ExecutionPreference preference) {
+ SCOPED_TRACE(message + " [prepareModel_1_1]");
+
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_1(model, preference, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+ ASSERT_EQ(nullptr, preparedModel.get());
+}
+
+static bool validExecutionPreference(ExecutionPreference preference) {
+ return preference == ExecutionPreference::LOW_POWER ||
+ preference == ExecutionPreference::FAST_SINGLE_ANSWER ||
+ preference == ExecutionPreference::SUSTAINED_SPEED;
+}
+
+// Primary validation function. This function will take a valid model, apply a
+// mutation to it to invalidate the model, then pass it to interface calls that
+// use the model. Note that the model here is passed by value, and any mutation
+// to the model does not leave this function.
+static void validate(const sp<IDevice>& device, const std::string& message, V1_1::Model model,
+ const std::function<void(Model*)>& mutation,
+ ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
+ mutation(&model);
+ if (validExecutionPreference(preference)) {
+ validateGetSupportedOperations(device, message, model);
+ }
+ validatePrepareModel(device, message, model, preference);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+ if (vec) {
+ std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+ vec->resize(vec->size() - 1);
+ }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+ // assume vec is valid
+ const uint32_t index = vec->size();
+ vec->resize(index + 1);
+ (*vec)[index] = value;
+ return index;
+}
+
+static uint32_t addOperand(Model* model) {
+ return hidl_vec_push_back(&model->operands,
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::MODEL_INPUT,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ });
+}
+
+static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
+ uint32_t index = addOperand(model);
+ model->operands[index].numberOfConsumers = 1;
+ model->operands[index].lifetime = lifetime;
+ return index;
+}
+
+///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
+
+static const int32_t invalidOperandTypes[] = {
+ static_cast<int32_t>(OperandType::FLOAT32) - 1, // lower bound fundamental
+ static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental
+ static_cast<int32_t>(OperandType::OEM) - 1, // lower bound OEM
+ static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM
+};
+
+static void mutateOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (int32_t invalidOperandType : invalidOperandTypes) {
+ const std::string message = "mutateOperandTypeTest: operand " +
+ std::to_string(operand) + " set to value " +
+ std::to_string(invalidOperandType);
+ validate(device, message, model, [operand, invalidOperandType](Model* model) {
+ model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE OPERAND RANK /////////////////////////
+
+static uint32_t getInvalidRank(OperandType type) {
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ return 1;
+ case OperandType::TENSOR_FLOAT32:
+ case OperandType::TENSOR_INT32:
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void mutateOperandRankTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+ const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
+ " has rank of " + std::to_string(invalidRank);
+ validate(device, message, model, [operand, invalidRank](Model* model) {
+ model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ });
+ }
+}
+
+///////////////////////// VALIDATE OPERAND SCALE /////////////////////////
+
+static float getInvalidScale(OperandType type) {
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ case OperandType::TENSOR_FLOAT32:
+ return 1.0f;
+ case OperandType::TENSOR_INT32:
+ return -1.0f;
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ return 0.0f;
+ default:
+ return 0.0f;
+ }
+}
+
+static void mutateOperandScaleTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const float invalidScale = getInvalidScale(model.operands[operand].type);
+ const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
+ " has scale of " + std::to_string(invalidScale);
+ validate(device, message, model, [operand, invalidScale](Model* model) {
+ model->operands[operand].scale = invalidScale;
+ });
+ }
+}
+
+///////////////////////// VALIDATE OPERAND ZERO POINT /////////////////////////
+
+static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ case OperandType::TENSOR_FLOAT32:
+ case OperandType::TENSOR_INT32:
+ return {1};
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ return {-1, 256};
+ default:
+ return {};
+ }
+}
+
+static void mutateOperandZeroPointTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const std::vector<int32_t> invalidZeroPoints =
+ getInvalidZeroPoints(model.operands[operand].type);
+ for (int32_t invalidZeroPoint : invalidZeroPoints) {
+ const std::string message = "mutateOperandZeroPointTest: operand " +
+ std::to_string(operand) + " has zero point of " +
+ std::to_string(invalidZeroPoint);
+ validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
+ model->operands[operand].zeroPoint = invalidZeroPoint;
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE EXTRA ??? /////////////////////////
+
+// TODO: Operand::lifetime
+// TODO: Operand::location
+
+///////////////////////// VALIDATE OPERATION OPERAND TYPE /////////////////////////
+
+static void mutateOperand(Operand* operand, OperandType type) {
+ Operand newOperand = *operand;
+ newOperand.type = type;
+ switch (type) {
+ case OperandType::FLOAT32:
+ case OperandType::INT32:
+ case OperandType::UINT32:
+ newOperand.dimensions = hidl_vec<uint32_t>();
+ newOperand.scale = 0.0f;
+ newOperand.zeroPoint = 0;
+ break;
+ case OperandType::TENSOR_FLOAT32:
+ newOperand.dimensions =
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ newOperand.scale = 0.0f;
+ newOperand.zeroPoint = 0;
+ break;
+ case OperandType::TENSOR_INT32:
+ newOperand.dimensions =
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ newOperand.zeroPoint = 0;
+ break;
+ case OperandType::TENSOR_QUANT8_ASYMM:
+ newOperand.dimensions =
+ operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
+ newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
+ break;
+ case OperandType::OEM:
+ case OperandType::TENSOR_OEM_BYTE:
+ default:
+ break;
+ }
+ *operand = newOperand;
+}
+
+static bool mutateOperationOperandTypeSkip(size_t operand, const V1_1::Model& model) {
+ // LSH_PROJECTION's second argument is allowed to have any type. This is the
+ // only operation that currently has a type that can be anything independent
+ // from any other type. Changing the operand type to any other type will
+ // result in a valid model for LSH_PROJECTION. If this is the case, skip the
+ // test.
+ for (const Operation& operation : model.operations) {
+ if (operation.type == OperationType::LSH_PROJECTION && operand == operation.inputs[1]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ if (mutateOperationOperandTypeSkip(operand, model)) {
+ continue;
+ }
+ for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
+ // Do not test OEM types
+ if (invalidOperandType == model.operands[operand].type ||
+ invalidOperandType == OperandType::OEM ||
+ invalidOperandType == OperandType::TENSOR_OEM_BYTE) {
+ continue;
+ }
+ const std::string message = "mutateOperationOperandTypeTest: operand " +
+ std::to_string(operand) + " set to type " +
+ toString(invalidOperandType);
+ validate(device, message, model, [operand, invalidOperandType](Model* model) {
+ mutateOperand(&model->operands[operand], invalidOperandType);
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
+
+static const int32_t invalidOperationTypes[] = {
+ static_cast<int32_t>(OperationType::ADD) - 1, // lower bound fundamental
+ static_cast<int32_t>(OperationType::TRANSPOSE) + 1, // upper bound fundamental
+ static_cast<int32_t>(OperationType::OEM_OPERATION) - 1, // lower bound OEM
+ static_cast<int32_t>(OperationType::OEM_OPERATION) + 1, // upper bound OEM
+};
+
+static void mutateOperationTypeTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (int32_t invalidOperationType : invalidOperationTypes) {
+ const std::string message = "mutateOperationTypeTest: operation " +
+ std::to_string(operation) + " set to value " +
+ std::to_string(invalidOperationType);
+ validate(device, message, model, [operation, invalidOperationType](Model* model) {
+ model->operations[operation].type =
+ static_cast<OperationType>(invalidOperationType);
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device,
+ const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.operands.size();
+ for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ const std::string message = "mutateOperationInputOperandIndexTest: operation " +
+ std::to_string(operation) + " input " +
+ std::to_string(input);
+ validate(device, message, model, [operation, input, invalidOperand](Model* model) {
+ model->operations[operation].inputs[input] = invalidOperand;
+ });
+ }
+ }
+}
+
+///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
+
+static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device,
+ const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.operands.size();
+ for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
+ std::to_string(operation) + " output " +
+ std::to_string(output);
+ validate(device, message, model, [operation, output, invalidOperand](Model* model) {
+ model->operations[operation].outputs[output] = invalidOperand;
+ });
+ }
+ }
+}
+
+///////////////////////// REMOVE OPERAND FROM EVERYTHING /////////////////////////
+
+static void removeValueAndDecrementGreaterValues(hidl_vec<uint32_t>* vec, uint32_t value) {
+ if (vec) {
+ // remove elements matching "value"
+ auto last = std::remove(vec->begin(), vec->end(), value);
+ vec->resize(std::distance(vec->begin(), last));
+
+ // decrement elements exceeding "value"
+ std::transform(vec->begin(), vec->end(), vec->begin(),
+ [value](uint32_t v) { return v > value ? v-- : v; });
+ }
+}
+
+static void removeOperand(Model* model, uint32_t index) {
+ hidl_vec_removeAt(&model->operands, index);
+ for (Operation& operation : model->operations) {
+ removeValueAndDecrementGreaterValues(&operation.inputs, index);
+ removeValueAndDecrementGreaterValues(&operation.outputs, index);
+ }
+ removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+}
+
+static void removeOperandTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ const std::string message = "removeOperandTest: operand " + std::to_string(operand);
+ validate(device, message, model,
+ [operand](Model* model) { removeOperand(model, operand); });
+ }
+}
+
+///////////////////////// REMOVE OPERATION /////////////////////////
+
+static void removeOperation(Model* model, uint32_t index) {
+ for (uint32_t operand : model->operations[index].inputs) {
+ model->operands[operand].numberOfConsumers--;
+ }
+ hidl_vec_removeAt(&model->operations, index);
+}
+
+static void removeOperationTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const std::string message = "removeOperationTest: operation " + std::to_string(operation);
+ validate(device, message, model,
+ [operation](Model* model) { removeOperation(model, operation); });
+ }
+}
+
+///////////////////////// REMOVE OPERATION INPUT /////////////////////////
+
+static void removeOperationInputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ const V1_1::Operation& op = model.operations[operation];
+ // CONCATENATION has at least 2 inputs, with the last element being
+ // INT32. Skip this test if removing one of CONCATENATION's
+ // inputs still produces a valid model.
+ if (op.type == V1_1::OperationType::CONCATENATION && op.inputs.size() > 2 &&
+ input != op.inputs.size() - 1) {
+ continue;
+ }
+ const std::string message = "removeOperationInputTest: operation " +
+ std::to_string(operation) + ", input " +
+ std::to_string(input);
+ validate(device, message, model, [operation, input](Model* model) {
+ uint32_t operand = model->operations[operation].inputs[input];
+ model->operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ });
+ }
+ }
+}
+
+///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
+
+static void removeOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ const std::string message = "removeOperationOutputTest: operation " +
+ std::to_string(operation) + ", output " +
+ std::to_string(output);
+ validate(device, message, model, [operation, output](Model* model) {
+ hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ });
+ }
+ }
+}
+
+///////////////////////// MODEL VALIDATION /////////////////////////
+
+// TODO: remove model input
+// TODO: remove model output
+// TODO: add unused operation
+
+///////////////////////// ADD OPERATION INPUT /////////////////////////
+
+static void addOperationInputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
+ validate(device, message, model, [operation](Model* model) {
+ uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
+ hidl_vec_push_back(&model->operations[operation].inputs, index);
+ hidl_vec_push_back(&model->inputIndexes, index);
+ });
+ }
+}
+
+///////////////////////// ADD OPERATION OUTPUT /////////////////////////
+
+static void addOperationOutputTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ const std::string message =
+ "addOperationOutputTest: operation " + std::to_string(operation);
+ validate(device, message, model, [operation](Model* model) {
+ uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
+ hidl_vec_push_back(&model->operations[operation].outputs, index);
+ hidl_vec_push_back(&model->outputIndexes, index);
+ });
+ }
+}
+
+///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
+
+static const int32_t invalidExecutionPreferences[] = {
+ static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
+ static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
+};
+
+static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (int32_t preference : invalidExecutionPreferences) {
+ const std::string message =
+ "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+ validate(device, message, model, [](Model*) {},
+ static_cast<ExecutionPreference>(preference));
+ }
+}
+
+////////////////////////// ENTRY POINT //////////////////////////////
+
+void ValidationTest::validateModel(const V1_1::Model& model) {
+ mutateOperandTypeTest(device, model);
+ mutateOperandRankTest(device, model);
+ mutateOperandScaleTest(device, model);
+ mutateOperandZeroPointTest(device, model);
+ mutateOperationOperandTypeTest(device, model);
+ mutateOperationTypeTest(device, model);
+ mutateOperationInputOperandIndexTest(device, model);
+ mutateOperationOutputOperandIndexTest(device, model);
+ removeOperandTest(device, model);
+ removeOperationTest(device, model);
+ removeOperationInputTest(device, model);
+ removeOperationOutputTest(device, model);
+ addOperationInputTest(device, model);
+ addOperationOutputTest(device, model);
+ mutateExecutionPreferenceTest(device, model);
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
+using ::android::hidl::memory::V1_0::IMemory;
+using test_helper::MixedTyped;
+using test_helper::MixedTypedExampleType;
+using test_helper::for_all;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void createPreparedModel(const sp<IDevice>& device, const V1_1::Model& model,
+ sp<IPreparedModel>* preparedModel) {
+ ASSERT_NE(nullptr, preparedModel);
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_1(
+ model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
+ ASSERT_EQ(ErrorStatus::NONE, status);
+ ASSERT_NE(0ul, supported.size());
+ fullySupportsModel =
+ std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
+ });
+ ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
+
+ // launch prepare model
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
+
+ // retrieve prepared model
+ preparedModelCallback->wait();
+ ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
+ *preparedModel = preparedModelCallback->getPreparedModel();
+
+ // The getSupportedOperations_1_1 call returns a list of operations that are
+ // guaranteed not to fail if prepareModel_1_1 is called, and
+ // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
+ // If a driver has any doubt that it can prepare an operation, it must
+ // return false. So here, if a driver isn't sure if it can support an
+ // operation, but reports that it successfully prepared the model, the test
+ // can continue.
+ if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
+ ASSERT_EQ(nullptr, preparedModel->get());
+ LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot "
+ "prepare model that it does not support.";
+ std::cout << "[ ] Unable to test Request validation because vendor service "
+ "cannot prepare model that it does not support."
+ << std::endl;
+ return;
+ }
+ ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ ASSERT_NE(nullptr, preparedModel->get());
+}
+
+// Primary validation function. This function will take a valid request, apply a
+// mutation to it to invalidate the request, then pass it to interface calls
+// that use the request. Note that the request here is passed by value, and any
+// mutation to the request does not leave this function.
+static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
+ Request request, const std::function<void(Request*)>& mutation) {
+ mutation(&request);
+ SCOPED_TRACE(message + " [execute]");
+
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ ASSERT_NE(nullptr, executionCallback.get());
+ Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
+ ASSERT_TRUE(executeLaunchStatus.isOk());
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
+
+ executionCallback->wait();
+ ErrorStatus executionReturnStatus = executionCallback->getStatus();
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
+}
+
+// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
+// so this is efficiently accomplished by moving the element to the end and
+// resizing the hidl_vec to one less.
+template <typename Type>
+static void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
+ if (vec) {
+ std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
+ vec->resize(vec->size() - 1);
+ }
+}
+
+template <typename Type>
+static uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
+ // assume vec is valid
+ const uint32_t index = vec->size();
+ vec->resize(index + 1);
+ (*vec)[index] = value;
+ return index;
+}
+
+///////////////////////// REMOVE INPUT ////////////////////////////////////
+
+static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ for (size_t input = 0; input < request.inputs.size(); ++input) {
+ const std::string message = "removeInput: removed input " + std::to_string(input);
+ validate(preparedModel, message, request,
+ [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); });
+ }
+}
+
+///////////////////////// REMOVE OUTPUT ////////////////////////////////////
+
+static void removeOutputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ for (size_t output = 0; output < request.outputs.size(); ++output) {
+ const std::string message = "removeOutput: removed Output " + std::to_string(output);
+ validate(preparedModel, message, request,
+ [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); });
+ }
+}
+
+///////////////////////////// ENTRY POINT //////////////////////////////////
+
+std::vector<Request> createRequests(const std::vector<MixedTypedExampleType>& examples) {
+ const uint32_t INPUT = 0;
+ const uint32_t OUTPUT = 1;
+
+ std::vector<Request> requests;
+
+ for (auto& example : examples) {
+ const MixedTyped& inputs = example.first;
+ const MixedTyped& outputs = example.second;
+
+ std::vector<RequestArgument> inputs_info, outputs_info;
+ uint32_t inputSize = 0, outputSize = 0;
+
+ // This function only partially specifies the metadata (vector of RequestArguments).
+ // The contents are copied over below.
+ for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
+ if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ RequestArgument arg_empty = {
+ .hasNoValue = true,
+ };
+ inputs_info[index] = s ? arg : arg_empty;
+ inputSize += s;
+ });
+ // Compute offset for inputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : inputs_info) {
+ if (!i.hasNoValue) i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+
+ // Go through all outputs, initialize RequestArgument descriptors
+ for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
+ if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
+ RequestArgument arg = {
+ .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
+ .dimensions = {},
+ };
+ outputs_info[index] = arg;
+ outputSize += s;
+ });
+ // Compute offset for outputs 1 and so on
+ {
+ size_t offset = 0;
+ for (auto& i : outputs_info) {
+ i.location.offset = offset;
+ offset += i.location.length;
+ }
+ }
+ std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
+ nn::allocateSharedMemory(outputSize)};
+ if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
+ return {};
+ }
+
+ // map pool
+ sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
+ if (inputMemory == nullptr) {
+ return {};
+ }
+ char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
+ if (inputPtr == nullptr) {
+ return {};
+ }
+
+ // initialize pool
+ inputMemory->update();
+ for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
+ char* begin = (char*)p;
+ char* end = begin + s;
+ // TODO: handle more than one input
+ std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
+ });
+ inputMemory->commit();
+
+ requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
+ }
+
+ return requests;
+}
+
+void ValidationTest::validateRequests(const V1_1::Model& model,
+ const std::vector<Request>& requests) {
+ // create IPreparedModel
+ sp<IPreparedModel> preparedModel;
+ ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel));
+ if (preparedModel == nullptr) {
+ return;
+ }
+
+ // validate each request
+ for (const Request& request : requests) {
+ removeInputTest(preparedModel, request);
+ removeOutputTest(preparedModel, request);
+ }
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/ValidationTests.cpp b/neuralnetworks/1.1/vts/functional/ValidationTests.cpp
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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_hidl_hal_test"
+
+#include "Models.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_1 {
+namespace vts {
+namespace functional {
+
+// forward declarations
+std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples);
+
+// generate validation tests
+#define VTS_CURRENT_TEST_CASE(TestName) \
+ TEST_F(ValidationTest, TestName) { \
+ const Model model = TestName::createTestModel(); \
+ const std::vector<Request> requests = createRequests(TestName::examples); \
+ validateModel(model); \
+ validateRequests(model, requests); \
+ }
+
+FOR_EACH_TEST_MODEL(VTS_CURRENT_TEST_CASE)
+
+#undef VTS_CURRENT_TEST_CASE
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_1
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
similarity index 64%
rename from neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp
rename to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index b1d3be786c8305ae853c59d8f6572eb3059ed4b1..62381e679660d189a34902952d9c4c992bac0cd1 100644 (file)
rename from neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.cpp
rename to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index b1d3be786c8305ae853c59d8f6572eb3059ed4b1..62381e679660d189a34902952d9c4c992bac0cd1 100644 (file)
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include "VtsHalNeuralnetworksV1_1.h"
-#include "Utils.h"
-
-#include <android-base/logging.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::hidl_memory;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
+#include "VtsHalNeuralnetworks.h"
namespace android {
namespace hardware {
namespace vts {
namespace functional {
-// allocator helper
-hidl_memory allocateSharedMemory(int64_t size) {
- return nn::allocateSharedMemory(size);
-}
-
// A class for test environment setup
NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
}
void NeuralnetworksHidlEnvironment::registerTestServices() {
- registerTestService<V1_1::IDevice>();
+ registerTestService<IDevice>();
}
// The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
+
NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
void NeuralnetworksHidlTest::SetUp() {
- device = ::testing::VtsHalHidlTargetTestBase::getService<V1_1::IDevice>(
+ ::testing::VtsHalHidlTargetTestBase::SetUp();
+ device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
NeuralnetworksHidlEnvironment::getInstance());
ASSERT_NE(nullptr, device.get());
}
-void NeuralnetworksHidlTest::TearDown() {}
+void NeuralnetworksHidlTest::TearDown() {
+ device = nullptr;
+ ::testing::VtsHalHidlTargetTestBase::TearDown();
+}
} // namespace functional
} // namespace vts
+
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus) {
+ return os << toString(errorStatus);
+}
+
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus) {
+ return os << toString(deviceStatus);
+}
+
} // namespace V1_1
} // namespace neuralnetworks
} // namespace hardware
} // namespace android
+
+using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
+ ::testing::InitGoogleTest(&argc, argv);
+ NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
+
+ int status = RUN_ALL_TESTS();
+ return status;
+}
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
similarity index 60%
rename from neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
rename to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 426246ce76f2c74ec1fc143e223e6c387a63dc5e..0050e52d257b870f3fbe5d3cf39f86206edf88f9 100644 (file)
rename from neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1.h
rename to neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 426246ce76f2c74ec1fc143e223e6c387a63dc5e..0050e52d257b870f3fbe5d3cf39f86206edf88f9 100644 (file)
#ifndef VTS_HAL_NEURALNETWORKS_V1_1_H
#define VTS_HAL_NEURALNETWORKS_V1_1_H
-#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
-#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
#include <android/hardware/neuralnetworks/1.1/IDevice.h>
#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
+
+#include <android-base/macros.h>
#include <gtest/gtest.h>
-#include <string>
+#include <iostream>
+#include <vector>
namespace android {
namespace hardware {
namespace neuralnetworks {
namespace V1_1 {
+
+using V1_0::Request;
+using V1_0::DeviceStatus;
+using V1_0::ErrorStatus;
+
namespace vts {
namespace functional {
-hidl_memory allocateSharedMemory(int64_t size);
// A class for test environment setup
class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
NeuralnetworksHidlEnvironment();
- NeuralnetworksHidlEnvironment(const NeuralnetworksHidlEnvironment&) = delete;
- NeuralnetworksHidlEnvironment(NeuralnetworksHidlEnvironment&&) = delete;
- NeuralnetworksHidlEnvironment& operator=(const NeuralnetworksHidlEnvironment&) = delete;
- NeuralnetworksHidlEnvironment& operator=(NeuralnetworksHidlEnvironment&&) = delete;
+ ~NeuralnetworksHidlEnvironment() override;
public:
- ~NeuralnetworksHidlEnvironment() override;
static NeuralnetworksHidlEnvironment* getInstance();
void registerTestServices() override;
};
// The main test class for NEURALNETWORKS HIDL HAL.
class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
+
public:
+ NeuralnetworksHidlTest();
~NeuralnetworksHidlTest() override;
void SetUp() override;
void TearDown() override;
- sp<V1_1::IDevice> device;
+ protected:
+ sp<IDevice> device;
};
+
+// Tag for the validation tests
+class ValidationTest : public NeuralnetworksHidlTest {
+ protected:
+ void validateModel(const Model& model);
+ void validateRequests(const Model& model, const std::vector<Request>& request);
+};
+
+// Tag for the generated tests
+class GeneratedTest : public NeuralnetworksHidlTest {};
+
} // namespace functional
} // namespace vts
// pretty-print values for error messages
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- V1_0::ErrorStatus errorStatus) {
- return os << toString(errorStatus);
-}
-
-template <typename CharT, typename Traits>
-::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& os,
- V1_0::DeviceStatus deviceStatus) {
- return os << toString(deviceStatus);
-}
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
} // namespace V1_1
} // namespace neuralnetworks
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2018 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_hidl_hal_test"
-
-#include "VtsHalNeuralnetworksV1_1.h"
-
-#include "Callbacks.h"
-#include "Models.h"
-#include "TestHarness.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Operand;
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::OperandType;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_1::Capabilities;
-using ::android::hardware::neuralnetworks::V1_1::IDevice;
-using ::android::hardware::neuralnetworks::V1_1::Model;
-using ::android::hardware::neuralnetworks::V1_1::Operation;
-using ::android::hardware::neuralnetworks::V1_1::OperationType;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_1 {
-namespace vts {
-namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-
-static void doPrepareModelShortcut(const sp<IDevice>& device, sp<IPreparedModel>* preparedModel) {
- ASSERT_NE(nullptr, preparedModel);
- Model model = createValidTestModel_1_1();
-
- // see if service can handle model
- bool fullySupportsModel = false;
- Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_1(
- model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
- ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_NE(0ul, supported.size());
- fullySupportsModel =
- std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
- });
- ASSERT_TRUE(supportedOpsLaunchStatus.isOk());
-
- // launch prepare model
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- // retrieve prepared model
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- *preparedModel = preparedModelCallback->getPreparedModel();
-
- // The getSupportedOperations call returns a list of operations that are
- // guaranteed not to fail if prepareModel is called, and
- // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
- // If a driver has any doubt that it can prepare an operation, it must
- // return false. So here, if a driver isn't sure if it can support an
- // operation, but reports that it successfully prepared the model, the test
- // can continue.
- if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
- ASSERT_EQ(nullptr, preparedModel->get());
- 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;
- return;
- }
- ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus);
- ASSERT_NE(nullptr, preparedModel->get());
-}
-
-// create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
-
-// status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
- Return<DeviceStatus> status = device->getStatus();
- ASSERT_TRUE(status.isOk());
- EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
-}
-
-// initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
- Return<void> ret =
- device->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
- EXPECT_EQ(ErrorStatus::NONE, status);
- EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
- EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
- EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
- EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
- EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.execTime);
- EXPECT_LT(0.0f, capabilities.relaxedFloat32toFloat16Performance.powerUsage);
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations positive test
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsPositiveTest) {
- Model model = createValidTestModel_1_1();
- Return<void> ret = device->getSupportedOperations_1_1(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- EXPECT_EQ(ErrorStatus::NONE, status);
- EXPECT_EQ(model.operations.size(), supported.size());
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 1
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest1) {
- Model model = createInvalidTestModel1_1_1();
- Return<void> ret = device->getSupportedOperations_1_1(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
- (void)supported;
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// supported operations negative test 2
-TEST_F(NeuralnetworksHidlTest, SupportedOperationsNegativeTest2) {
- Model model = createInvalidTestModel2_1_1();
- Return<void> ret = device->getSupportedOperations_1_1(
- model, [&](ErrorStatus status, const hidl_vec<bool>& supported) {
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
- (void)supported;
- });
- EXPECT_TRUE(ret.isOk());
-}
-
-// prepare simple model positive test
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelPositiveTest) {
- sp<IPreparedModel> preparedModel;
- doPrepareModelShortcut(device, &preparedModel);
-}
-
-// prepare simple model negative test 1
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest1) {
- Model model = createInvalidTestModel1_1_1();
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
- sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
- EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// prepare simple model negative test 2
-TEST_F(NeuralnetworksHidlTest, SimplePrepareModelNegativeTest2) {
- Model model = createInvalidTestModel2_1_1();
- sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
- ASSERT_TRUE(prepareLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
-
- preparedModelCallback->wait();
- ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
- sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
- EXPECT_EQ(nullptr, preparedModel.get());
-}
-
-// execute simple graph positive test
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphPositiveTest) {
- std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
- std::vector<float> expectedData = {6.0f, 8.0f, 10.0f, 12.0f};
- const uint32_t OUTPUT = 1;
-
- sp<IPreparedModel> preparedModel;
- ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
- if (preparedModel == nullptr) {
- return;
- }
- Request request = createValidTestRequest();
-
- auto postWork = [&] {
- sp<IMemory> outputMemory = mapMemory(request.pools[OUTPUT]);
- if (outputMemory == nullptr) {
- return false;
- }
- float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
- if (outputPtr == nullptr) {
- return false;
- }
- outputMemory->read();
- std::copy(outputPtr, outputPtr + outputData.size(), outputData.begin());
- outputMemory->commit();
- return true;
- };
-
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- executionCallback->on_finish(postWork);
- Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executeLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executeLaunchStatus));
-
- executionCallback->wait();
- ErrorStatus executionReturnStatus = executionCallback->getStatus();
- EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus);
- EXPECT_EQ(expectedData, outputData);
-}
-
-// execute simple graph negative test 1
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest1) {
- sp<IPreparedModel> preparedModel;
- ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
- if (preparedModel == nullptr) {
- return;
- }
- Request request = createInvalidTestRequest1();
-
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executeLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
- executionCallback->wait();
- ErrorStatus executionReturnStatus = executionCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-// execute simple graph negative test 2
-TEST_F(NeuralnetworksHidlTest, SimpleExecuteGraphNegativeTest2) {
- sp<IPreparedModel> preparedModel;
- ASSERT_NO_FATAL_FAILURE(doPrepareModelShortcut(device, &preparedModel));
- if (preparedModel == nullptr) {
- return;
- }
- Request request = createInvalidTestRequest2();
-
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executeLaunchStatus = preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executeLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
-
- executionCallback->wait();
- ErrorStatus executionReturnStatus = executionCallback->getStatus();
- EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
-}
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_1
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
-
-using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
- ::testing::InitGoogleTest(&argc, argv);
- NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
- int status = RUN_ALL_TESTS();
- return status;
-}
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1GeneratedTest.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 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_hidl_hal_test"
-
-#include "VtsHalNeuralnetworksV1_1.h"
-
-#include "Callbacks.h"
-#include "TestHarness.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
-using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
-using ::android::hardware::neuralnetworks::V1_0::Capabilities;
-using ::android::hardware::neuralnetworks::V1_0::DeviceStatus;
-using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
-using ::android::hardware::neuralnetworks::V1_0::FusedActivationFunc;
-using ::android::hardware::neuralnetworks::V1_0::Operand;
-using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
-using ::android::hardware::neuralnetworks::V1_0::OperandType;
-using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_1::IDevice;
-using ::android::hardware::neuralnetworks::V1_1::Model;
-using ::android::hardware::neuralnetworks::V1_1::Operation;
-using ::android::hardware::neuralnetworks::V1_1::OperationType;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-
-namespace generated_tests {
-using ::generated_tests::MixedTypedExampleType;
-extern void Execute(sp<V1_1::IDevice>&, std::function<Model(void)>, std::function<bool(int)>,
- const std::vector<MixedTypedExampleType>&);
-} // namespace generated_tests
-
-namespace V1_1 {
-namespace vts {
-namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
-
-// Mixed-typed examples
-typedef generated_tests::MixedTypedExampleType MixedTypedExample;
-
-// in frameworks/ml/nn/runtime/tests/generated/
-#include "all_generated_V1_0_vts_tests.cpp"
-#include "all_generated_V1_1_vts_tests.cpp"
-
-} // namespace functional
-} // namespace vts
-} // namespace V1_1
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
index 8c4ccf6bfe6f129c2589999d8552dfeaa71d58f7..2c1eb607cabc8138f8dfc184d8b5c5b3a7fcc040 100644 (file)
* Test IRadio.setGsmBroadcastConfig() for the response returned.
*/
TEST_F(RadioHidlTest, setGsmBroadcastConfig) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Create GsmBroadcastSmsConfigInfo #1
GsmBroadcastSmsConfigInfo gbSmsConfig1;
* Test IRadio.getGsmBroadcastConfig() for the response returned.
*/
TEST_F(RadioHidlTest, getGsmBroadcastConfig) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getGsmBroadcastConfig(serial);
* Test IRadio.setCdmaBroadcastConfig() for the response returned.
*/
TEST_F(RadioHidlTest, setCdmaBroadcastConfig) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
CdmaBroadcastSmsConfigInfo cbSmsConfig;
cbSmsConfig.serviceCategory = 4096;
* Test IRadio.getCdmaBroadcastConfig() for the response returned.
*/
TEST_F(RadioHidlTest, getCdmaBroadcastConfig) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCdmaBroadcastConfig(serial);
* Test IRadio.setCdmaBroadcastActivation() for the response returned.
*/
TEST_F(RadioHidlTest, setCdmaBroadcastActivation) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool activate = false;
radio->setCdmaBroadcastActivation(serial, activate);
* Test IRadio.setGsmBroadcastActivation() for the response returned.
*/
TEST_F(RadioHidlTest, setGsmBroadcastActivation) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool activate = false;
radio->setGsmBroadcastActivation(serial, activate);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
index 949668842f84768868a7ae0ffc9d74bd6aae93ca..4f10f112fcb691ab4e6d022f7da25208683b3a5c 100644 (file)
* Test IRadio.getDataRegistrationState() for the response returned.
*/
TEST_F(RadioHidlTest, getDataRegistrationState) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getDataRegistrationState(serial);
* Test IRadio.setupDataCall() for the response returned.
*/
TEST_F(RadioHidlTest, setupDataCall) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioTechnology radioTechnology = RadioTechnology::LTE;
radio->setupDataCall(serial, radioTechnology, dataProfileInfo, modemCognitive, roamingAllowed,
isRoaming);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(std::cv_status::no_timeout, wait(300));
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
* Test IRadio.deactivateDataCall() for the response returned.
*/
TEST_F(RadioHidlTest, deactivateDataCall) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
int cid = 1;
bool reasonRadioShutDown = false;
* Test IRadio.getDataCallList() for the response returned.
*/
TEST_F(RadioHidlTest, getDataCallList) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getDataCallList(serial);
* Test IRadio.setInitialAttachApn() for the response returned.
*/
TEST_F(RadioHidlTest, setInitialAttachApn) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
DataProfileInfo dataProfileInfo;
memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
* Test IRadio.setDataAllowed() for the response returned.
*/
TEST_F(RadioHidlTest, setDataAllowed) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool allow = true;
radio->setDataAllowed(serial, allow);
* Test IRadio.setDataProfile() for the response returned.
*/
TEST_F(RadioHidlTest, setDataProfile) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Create a dataProfileInfo
DataProfileInfo dataProfileInfo;
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
index e6c8934b7b8b689e8955052484686e2b828a5b5b..e6837ce1d0dc8ffb33bc07c69dcbca9fe613d3ea 100644 (file)
* Test IRadio.supplyIccPinForApp() for the response returned
*/
TEST_F(RadioHidlTest, supplyIccPinForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
// 3GPP2 apps only
* Test IRadio.supplyIccPukForApp() for the response returned.
*/
TEST_F(RadioHidlTest, supplyIccPukForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
// 3GPP2 apps only
* Test IRadio.supplyIccPin2ForApp() for the response returned.
*/
TEST_F(RadioHidlTest, supplyIccPin2ForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
// 3GPP2 apps only
* Test IRadio.supplyIccPuk2ForApp() for the response returned.
*/
TEST_F(RadioHidlTest, supplyIccPuk2ForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
// 3GPP2 apps only
* Test IRadio.changeIccPinForApp() for the response returned.
*/
TEST_F(RadioHidlTest, changeIccPinForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
// 3GPP2 apps only
* Test IRadio.changeIccPin2ForApp() for the response returned.
*/
TEST_F(RadioHidlTest, changeIccPin2ForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and
// 3GPP2 apps only
* Test IRadio.getImsiForApp() for the response returned.
*/
TEST_F(RadioHidlTest, getImsiForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Check success returned while getting imsi for 3GPP and 3GPP2 apps only
for (int i = 0; i < (int)cardStatus.applications.size(); i++) {
* Test IRadio.iccIOForApp() for the response returned.
*/
TEST_F(RadioHidlTest, iccIOForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
for (int i = 0; i < (int)cardStatus.applications.size(); i++) {
IccIo iccIo;
* Test IRadio.iccTransmitApduBasicChannel() for the response returned.
*/
TEST_F(RadioHidlTest, iccTransmitApduBasicChannel) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
SimApdu msg;
memset(&msg, 0, sizeof(msg));
msg.data = hidl_string();
* Test IRadio.iccOpenLogicalChannel() for the response returned.
*/
TEST_F(RadioHidlTest, iccOpenLogicalChannel) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
int p2 = 0x04;
// Specified in ISO 7816-4 clause 7.1.1 0x04 means that FCP template is requested.
for (int i = 0; i < (int)cardStatus.applications.size(); i++) {
* Test IRadio.iccCloseLogicalChannel() for the response returned.
*/
TEST_F(RadioHidlTest, iccCloseLogicalChannel) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Try closing invalid channel and check INVALID_ARGUMENTS returned as error
radio->iccCloseLogicalChannel(serial, 0);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.iccTransmitApduLogicalChannel() for the response returned.
*/
TEST_F(RadioHidlTest, iccTransmitApduLogicalChannel) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
SimApdu msg;
memset(&msg, 0, sizeof(msg));
msg.data = hidl_string();
* Test IRadio.requestIccSimAuthentication() for the response returned.
*/
TEST_F(RadioHidlTest, requestIccSimAuthentication) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Pass wrong challenge string and check RadioError::INVALID_ARGUMENTS
- // returned as error.
+ // or REQUEST_NOT_SUPPORTED returned as error.
for (int i = 0; i < (int)cardStatus.applications.size(); i++) {
radio->requestIccSimAuthentication(serial, 0, hidl_string("test"),
cardStatus.applications[i].aidPtr);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
- EXPECT_EQ(RadioError::INVALID_ARGUMENTS, radioRsp->rspInfo.error);
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::INVALID_ARGUMENTS,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
* Test IRadio.supplyNetworkDepersonalization() for the response returned.
*/
TEST_F(RadioHidlTest, supplyNetworkDepersonalization) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->supplyNetworkDepersonalization(serial, hidl_string("test"));
EXPECT_EQ(std::cv_status::no_timeout, wait());
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
index 45746784dee37fba6ec62a946a61d5f08fb8ccbc..4331c06c858b09ca6d462626e1294938566d6dbe 100644 (file)
* Test IRadio.getClir() for the response returned.
*/
TEST_F(RadioHidlTest, getClir) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getClir(serial);
* Test IRadio.setClir() for the response returned.
*/
TEST_F(RadioHidlTest, setClir) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
int32_t status = 1;
radio->setClir(serial, status);
* Test IRadio.getFacilityLockForApp() for the response returned.
*/
TEST_F(RadioHidlTest, getFacilityLockForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
std::string facility = "";
std::string password = "";
int32_t serviceClass = 1;
* Test IRadio.setFacilityLockForApp() for the response returned.
*/
TEST_F(RadioHidlTest, setFacilityLockForApp) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
std::string facility = "";
bool lockState = false;
std::string password = "";
* Test IRadio.setBarringPassword() for the response returned.
*/
TEST_F(RadioHidlTest, setBarringPassword) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
std::string facility = "";
std::string oldPassword = "";
std::string newPassword = "";
* Test IRadio.getClip() for the response returned.
*/
TEST_F(RadioHidlTest, getClip) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getClip(serial);
* Test IRadio.setSuppServiceNotifications() for the response returned.
*/
TEST_F(RadioHidlTest, setSuppServiceNotifications) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool enable = false;
radio->setSuppServiceNotifications(serial, enable);
* Test IRadio.requestIsimAuthentication() for the response returned.
*/
TEST_F(RadioHidlTest, requestIsimAuthentication) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
std::string challenge = "";
radio->requestIsimAuthentication(serial, challenge);
* Test IRadio.getImsRegistrationState() for the response returned.
*/
TEST_F(RadioHidlTest, getImsRegistrationState) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getImsRegistrationState(serial);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index e5268f632bce690c61fa2efb09b43588b1f12de6..6b7add547173893c8d64b09473aaf161ee0ed3d4 100644 (file)
* Test IRadio.getSignalStrength() for the response returned.
*/
TEST_F(RadioHidlTest, getSignalStrength) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getSignalStrength(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getVoiceRegistrationState() for the response returned.
*/
TEST_F(RadioHidlTest, getVoiceRegistrationState) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getVoiceRegistrationState(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getOperator() for the response returned.
*/
TEST_F(RadioHidlTest, getOperator) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getOperator(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setRadioPower() for the response returned.
*/
TEST_F(RadioHidlTest, setRadioPower) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setRadioPower(serial, 1);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getNetworkSelectionMode() for the response returned.
*/
TEST_F(RadioHidlTest, getNetworkSelectionMode) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getNetworkSelectionMode(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setNetworkSelectionModeAutomatic() for the response returned.
*/
TEST_F(RadioHidlTest, setNetworkSelectionModeAutomatic) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setNetworkSelectionModeAutomatic(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setNetworkSelectionModeManual() for the response returned.
*/
TEST_F(RadioHidlTest, setNetworkSelectionModeManual) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setNetworkSelectionModeManual(serial, "123456");
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getAvailableNetworks() for the response returned.
*/
TEST_F(RadioHidlTest, getAvailableNetworks) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getAvailableNetworks(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait(300));
* Test IRadio.getBasebandVersion() for the response returned.
*/
TEST_F(RadioHidlTest, getBasebandVersion) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getBasebandVersion(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setBandMode() for the response returned.
*/
TEST_F(RadioHidlTest, setBandMode) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setBandMode(serial, RadioBandMode::BAND_MODE_USA);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getAvailableBandModes() for the response returned.
*/
TEST_F(RadioHidlTest, getAvailableBandModes) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getAvailableBandModes(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setPreferredNetworkType() for the response returned.
*/
TEST_F(RadioHidlTest, setPreferredNetworkType) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setPreferredNetworkType(serial, PreferredNetworkType::GSM_ONLY);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getPreferredNetworkType() for the response returned.
*/
TEST_F(RadioHidlTest, getPreferredNetworkType) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getPreferredNetworkType(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getNeighboringCids() for the response returned.
*/
TEST_F(RadioHidlTest, getNeighboringCids) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getNeighboringCids(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setLocationUpdates() for the response returned.
*/
TEST_F(RadioHidlTest, setLocationUpdates) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setLocationUpdates(serial, true);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setCdmaRoamingPreference() for the response returned.
*/
TEST_F(RadioHidlTest, setCdmaRoamingPreference) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setCdmaRoamingPreference(serial, CdmaRoamingType::HOME_NETWORK);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getCdmaRoamingPreference() for the response returned.
*/
TEST_F(RadioHidlTest, getCdmaRoamingPreference) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCdmaRoamingPreference(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getTTYMode() for the response returned.
*/
TEST_F(RadioHidlTest, getTTYMode) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getTTYMode(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setTTYMode() for the response returned.
*/
TEST_F(RadioHidlTest, setTTYMode) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setTTYMode(serial, TtyMode::OFF);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setPreferredVoicePrivacy() for the response returned.
*/
TEST_F(RadioHidlTest, setPreferredVoicePrivacy) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setPreferredVoicePrivacy(serial, true);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getPreferredVoicePrivacy() for the response returned.
*/
TEST_F(RadioHidlTest, getPreferredVoicePrivacy) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getPreferredVoicePrivacy(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getCDMASubscription() for the response returned.
*/
TEST_F(RadioHidlTest, getCDMASubscription) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCDMASubscription(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getDeviceIdentity() for the response returned.
*/
TEST_F(RadioHidlTest, getDeviceIdentity) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getDeviceIdentity(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.exitEmergencyCallbackMode() for the response returned.
*/
TEST_F(RadioHidlTest, exitEmergencyCallbackMode) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->exitEmergencyCallbackMode(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getCdmaSubscriptionSource() for the response returned.
*/
TEST_F(RadioHidlTest, getCdmaSubscriptionSource) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCdmaSubscriptionSource(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setCdmaSubscriptionSource() for the response returned.
*/
TEST_F(RadioHidlTest, setCdmaSubscriptionSource) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setCdmaSubscriptionSource(serial, CdmaSubscriptionSource::RUIM_SIM);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getVoiceRadioTechnology() for the response returned.
*/
TEST_F(RadioHidlTest, getVoiceRadioTechnology) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getVoiceRadioTechnology(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getCellInfoList() for the response returned.
*/
TEST_F(RadioHidlTest, getCellInfoList) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCellInfoList(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setCellInfoListRate() for the response returned.
*/
TEST_F(RadioHidlTest, setCellInfoListRate) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// TODO(sanketpadawe): RIL crashes with value of rate = 10
radio->setCellInfoListRate(serial, 10);
* Test IRadio.nvReadItem() for the response returned.
*/
TEST_F(RadioHidlTest, nvReadItem) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->nvReadItem(serial, NvItem::LTE_BAND_ENABLE_25);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.nvWriteItem() for the response returned.
*/
TEST_F(RadioHidlTest, nvWriteItem) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
NvWriteItem item;
memset(&item, 0, sizeof(item));
item.value = hidl_string();
* Test IRadio.nvWriteCdmaPrl() for the response returned.
*/
TEST_F(RadioHidlTest, nvWriteCdmaPrl) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
std::vector<uint8_t> prl = {1, 2, 3, 4, 5};
radio->nvWriteCdmaPrl(serial, hidl_vec<uint8_t>(prl));
* Test IRadio.nvResetConfig() for the response returned.
*/
TEST_F(RadioHidlTest, nvResetConfig) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
- radio->nvResetConfig(++serial, ResetNvType::ERASE);
+ radio->nvResetConfig(serial, ResetNvType::ERASE);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
* Test IRadio.setUiccSubscription() for the response returned.
*/
TEST_F(RadioHidlTest, setUiccSubscription) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
SelectUiccSub item;
memset(&item, 0, sizeof(item));
* Test IRadio.getHardwareConfig() for the response returned.
*/
TEST_F(RadioHidlTest, getHardwareConfig) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getHardwareConfig(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.requestShutdown() for the response returned.
*/
TEST_F(RadioHidlTest, requestShutdown) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->requestShutdown(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getRadioCapability() for the response returned.
*/
TEST_F(RadioHidlTest, getRadioCapability) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getRadioCapability(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setRadioCapability() for the response returned.
*/
TEST_F(RadioHidlTest, setRadioCapability) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioCapability rc;
memset(&rc, 0, sizeof(rc));
rc.logicalModemUuid = hidl_string();
* Test IRadio.startLceService() for the response returned.
*/
TEST_F(RadioHidlTest, startLceService) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->startLceService(serial, 5, true);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.stopLceService() for the response returned.
*/
TEST_F(RadioHidlTest, stopLceService) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->stopLceService(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.pullLceData() for the response returned.
*/
TEST_F(RadioHidlTest, pullLceData) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->pullLceData(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getModemActivityInfo() for the response returned.
*/
TEST_F(RadioHidlTest, getModemActivityInfo) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getModemActivityInfo(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setAllowedCarriers() for the response returned.
*/
TEST_F(RadioHidlTest, setAllowedCarriers) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
CarrierRestrictions carriers;
memset(&carriers, 0, sizeof(carriers));
carriers.allowedCarriers.resize(1);
{RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
}
+ /* Setting to carrier restriction needs some time */
+ updateSimCardStatus();
+ auto startTime = std::chrono::system_clock::now();
+ while (cardStatus.cardState != CardState::RESTRICTED &&
+ std::chrono::duration_cast<chrono::seconds>(std::chrono::system_clock::now() - startTime)
+ .count() < 10) {
+ /* Set 2 seconds as interval to check card status */
+ sleep(2);
+ updateSimCardStatus();
+ }
+ EXPECT_EQ(CardState::RESTRICTED, cardStatus.cardState);
+ sleep(10);
+
/* Reset back to no carrier restriction */
memset(&carriers, 0, sizeof(carriers));
carriers.allowedCarriers.resize(0);
carriers.excludedCarriers.resize(0);
- radio->setAllowedCarriers(++serial, true, carriers);
+ serial = GetRandomSerialNumber();
+ radio->setAllowedCarriers(serial, true, carriers);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error,
{RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
}
+
+ /* Resetting back to no carrier restriction needs some time */
+ updateSimCardStatus();
+ startTime = std::chrono::system_clock::now();
+ while (cardStatus.cardState == CardState::RESTRICTED &&
+ std::chrono::duration_cast<chrono::seconds>(std::chrono::system_clock::now() - startTime)
+ .count() < 10) {
+ /* Set 2 seconds as interval to check card status */
+ sleep(2);
+ updateSimCardStatus();
+ }
+ EXPECT_NE(CardState::RESTRICTED, cardStatus.cardState);
+ sleep(10);
}
/*
* Test IRadio.getAllowedCarriers() for the response returned.
*/
TEST_F(RadioHidlTest, getAllowedCarriers) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getAllowedCarriers(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.sendDeviceState() for the response returned.
*/
TEST_F(RadioHidlTest, sendDeviceState) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->sendDeviceState(serial, DeviceStateType::POWER_SAVE_MODE, true);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setIndicationFilter() for the response returned.
*/
TEST_F(RadioHidlTest, setIndicationFilter) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setIndicationFilter(serial, 1);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setSimCardPower() for the response returned.
*/
TEST_F(RadioHidlTest, setSimCardPower) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setSimCardPower(serial, true);
EXPECT_EQ(std::cv_status::no_timeout, wait());
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
index 469f03aead580e157ac818b428518255e91c6f5f..9e4142960f25b00d2146cf8ecc5ee95ffc12fb7d 100644 (file)
* Test IRadio.sendSms() for the response returned.
*/
TEST_F(RadioHidlTest, sendSms) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
GsmSmsMessage msg;
msg.smscPdu = "";
msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
radio->sendSms(serial, msg);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(std::cv_status::no_timeout, wait(300));
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
* Test IRadio.sendSMSExpectMore() for the response returned.
*/
TEST_F(RadioHidlTest, sendSMSExpectMore) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
GsmSmsMessage msg;
msg.smscPdu = "";
msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
// TODO(shuoq): add more test for this API when inserted sim card is
// considered
- EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(std::cv_status::no_timeout, wait(300));
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
* Test IRadio.acknowledgeLastIncomingGsmSms() for the response returned.
*/
TEST_F(RadioHidlTest, acknowledgeLastIncomingGsmSms) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool success = true;
radio->acknowledgeLastIncomingGsmSms(serial, success,
* Test IRadio.acknowledgeIncomingGsmSmsWithPdu() for the response returned.
*/
TEST_F(RadioHidlTest, acknowledgeIncomingGsmSmsWithPdu) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool success = true;
std::string ackPdu = "";
* Test IRadio.sendCdmaSms() for the response returned.
*/
TEST_F(RadioHidlTest, sendCdmaSms) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Create a CdmaSmsAddress
CdmaSmsAddress cdmaSmsAddress;
* Test IRadio.acknowledgeLastIncomingCdmaSms() for the response returned.
*/
TEST_F(RadioHidlTest, acknowledgeLastIncomingCdmaSms) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Create a CdmaSmsAck
CdmaSmsAck cdmaSmsAck;
* Test IRadio.sendImsSms() for the response returned.
*/
TEST_F(RadioHidlTest, sendImsSms) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Create a CdmaSmsAddress
CdmaSmsAddress cdmaSmsAddress;
* Test IRadio.getSmscAddress() for the response returned.
*/
TEST_F(RadioHidlTest, getSmscAddress) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getSmscAddress(serial);
* Test IRadio.setSmscAddress() for the response returned.
*/
TEST_F(RadioHidlTest, setSmscAddress) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
hidl_string address = hidl_string("smscAddress");
radio->setSmscAddress(serial, address);
* Test IRadio.writeSmsToSim() for the response returned.
*/
TEST_F(RadioHidlTest, writeSmsToSim) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
SmsWriteArgs smsWriteArgs;
smsWriteArgs.status = SmsWriteArgsStatus::REC_UNREAD;
smsWriteArgs.smsc = "";
* Test IRadio.deleteSmsOnSim() for the response returned.
*/
TEST_F(RadioHidlTest, deleteSmsOnSim) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
int index = 1;
radio->deleteSmsOnSim(serial, index);
* Test IRadio.writeSmsToRuim() for the response returned.
*/
TEST_F(RadioHidlTest, writeSmsToRuim) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Create a CdmaSmsAddress
CdmaSmsAddress cdmaSmsAddress;
* Test IRadio.deleteSmsOnRuim() for the response returned.
*/
TEST_F(RadioHidlTest, deleteSmsOnRuim) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
int index = 1;
// Create a CdmaSmsAddress
* Test IRadio.reportSmsMemoryStatus() for the response returned.
*/
TEST_F(RadioHidlTest, reportSmsMemoryStatus) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool available = true;
radio->reportSmsMemoryStatus(serial, available);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
index 411d74c22b9353ceb4e8e0b0b304fdbe6e5ae38f..a3b5029f459a43038af9d83355924dedc5c30347 100644 (file)
* Test IRadio.sendEnvelope() for the response returned.
*/
TEST_F(RadioHidlTest, sendEnvelope) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Test with sending empty string
std::string content = "";
* Test IRadio.sendTerminalResponseToSim() for the response returned.
*/
TEST_F(RadioHidlTest, sendTerminalResponseToSim) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Test with sending empty string
std::string commandResponse = "";
* Test IRadio.handleStkCallSetupRequestFromSim() for the response returned.
*/
TEST_F(RadioHidlTest, handleStkCallSetupRequestFromSim) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
bool accept = false;
radio->handleStkCallSetupRequestFromSim(serial, accept);
* Test IRadio.reportStkServiceIsRunning() for the response returned.
*/
TEST_F(RadioHidlTest, reportStkServiceIsRunning) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->reportStkServiceIsRunning(serial);
* string.
*/
TEST_F(RadioHidlTest, sendEnvelopeWithStatus) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
// Test with sending empty string
std::string contents = "";
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
index e3e70042c4a1efc069599e12d16e24d04f2a4b06..984fa1c2c55899d5d8aedb325fbc96be06945bc4 100644 (file)
radio->setResponseFunctions(radioRsp, radioInd);
- int serial = GetRandomSerialNumber();
- radio->getIccCardStatus(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
+ updateSimCardStatus();
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error);
- /* Vts Testing with Sim Absent only. This needs to be removed later in P when sim present
- * scenarios will be tested. */
- EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
+ /* Enforce Vts Testing with Sim Status Present only. */
+ EXPECT_EQ(CardState::PRESENT, cardStatus.cardState);
}
-void RadioHidlTest::notify() {
+void RadioHidlTest::notify(int receivedSerial) {
std::unique_lock<std::mutex> lock(mtx);
- count++;
- cv.notify_one();
+ if (serial == receivedSerial) {
+ count++;
+ cv.notify_one();
+ }
}
std::cv_status RadioHidlTest::wait(int sec) {
}
count--;
return status;
-}
\ No newline at end of file
+}
+
+void RadioHidlTest::updateSimCardStatus() {
+ serial = GetRandomSerialNumber();
+ radio->getIccCardStatus(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h b/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
index 6b95ab0d18a9701428bbe9c41cbcff46d0b5041c..e86f3ac5ac231dfb29422f58bb323358a53dcf0e 100644 (file)
std::condition_variable cv;
int count;
+ /* Serial number for radio request */
+ int serial;
+
+ /* Update Sim Card Status */
+ void updateSimCardStatus();
+
public:
virtual void SetUp() override;
/* Used as a mechanism to inform the test about data/event callback */
- void notify();
+ void notify(int receivedSerial);
/* Test code calls this function to wait for response */
std::cv_status wait(int sec = TIMEOUT_PERIOD);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
index b3d56480c14ea2ae666dd7ef33f4d3baa8805d02..4eddcf4f7a4319ceb737842fac1890b8db4caf29 100644 (file)
* Test IRadio.getCurrentCalls() for the response returned.
*/
TEST_F(RadioHidlTest, getCurrentCalls) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCurrentCalls(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.dial() for the response returned.
*/
TEST_F(RadioHidlTest, dial) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Dial dialInfo;
memset(&dialInfo, 0, sizeof(dialInfo));
* Test IRadio.hangup() for the response returned.
*/
TEST_F(RadioHidlTest, hangup) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->hangup(serial, 1);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.hangupWaitingOrBackground() for the response returned.
*/
TEST_F(RadioHidlTest, hangupWaitingOrBackground) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->hangupWaitingOrBackground(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.hangupForegroundResumeBackground() for the response returned.
*/
TEST_F(RadioHidlTest, hangupForegroundResumeBackground) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->hangupForegroundResumeBackground(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.switchWaitingOrHoldingAndActive() for the response returned.
*/
TEST_F(RadioHidlTest, switchWaitingOrHoldingAndActive) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->switchWaitingOrHoldingAndActive(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.conference() for the response returned.
*/
TEST_F(RadioHidlTest, conference) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->conference(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.rejectCall() for the response returned.
*/
TEST_F(RadioHidlTest, rejectCall) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->rejectCall(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getLastCallFailCause() for the response returned.
*/
TEST_F(RadioHidlTest, getLastCallFailCause) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getLastCallFailCause(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.sendUssd() for the response returned.
*/
TEST_F(RadioHidlTest, sendUssd) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->sendUssd(serial, hidl_string("test"));
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
* Test IRadio.cancelPendingUssd() for the response returned.
*/
TEST_F(RadioHidlTest, cancelPendingUssd) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->cancelPendingUssd(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getCallForwardStatus() for the response returned.
*/
TEST_F(RadioHidlTest, getCallForwardStatus) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
CallForwardInfo callInfo;
memset(&callInfo, 0, sizeof(callInfo));
callInfo.number = hidl_string();
* Test IRadio.setCallForward() for the response returned.
*/
TEST_F(RadioHidlTest, setCallForward) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
CallForwardInfo callInfo;
memset(&callInfo, 0, sizeof(callInfo));
callInfo.number = hidl_string();
* Test IRadio.getCallWaiting() for the response returned.
*/
TEST_F(RadioHidlTest, getCallWaiting) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getCallWaiting(serial, 1);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setCallWaiting() for the response returned.
*/
TEST_F(RadioHidlTest, setCallWaiting) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setCallWaiting(serial, true, 1);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.acceptCall() for the response returned.
*/
TEST_F(RadioHidlTest, acceptCall) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->acceptCall(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.separateConnection() for the response returned.
*/
TEST_F(RadioHidlTest, separateConnection) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->separateConnection(serial, 1);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.explicitCallTransfer() for the response returned.
*/
TEST_F(RadioHidlTest, explicitCallTransfer) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->explicitCallTransfer(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.sendCDMAFeatureCode() for the response returned.
*/
TEST_F(RadioHidlTest, sendCDMAFeatureCode) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->sendCDMAFeatureCode(serial, hidl_string());
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.sendDtmf() for the response returned.
*/
TEST_F(RadioHidlTest, sendDtmf) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->sendDtmf(serial, "1");
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.startDtmf() for the response returned.
*/
TEST_F(RadioHidlTest, startDtmf) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->startDtmf(serial, "1");
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.stopDtmf() for the response returned.
*/
TEST_F(RadioHidlTest, stopDtmf) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->stopDtmf(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setMute() for the response returned.
*/
TEST_F(RadioHidlTest, setMute) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->setMute(serial, true);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.getMute() for the response returned.
*/
TEST_F(RadioHidlTest, getMute) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->getMute(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.sendBurstDtmf() for the response returned.
*/
TEST_F(RadioHidlTest, sendBurstDtmf) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio->sendBurstDtmf(serial, "1", 0, 0);
EXPECT_EQ(std::cv_status::no_timeout, wait());
diff --git a/radio/1.0/vts/functional/radio_response.cpp b/radio/1.0/vts/functional/radio_response.cpp
index 434d488f5f16a63ae8c5be44e7b356626286f30c..93d5557de36f8f065688f5e3b9c93f8fb820ddc7 100644 (file)
@@ -24,69 +24,69 @@ Return<void> RadioResponse::getIccCardStatusResponse(const RadioResponseInfo& in
const CardStatus& card_status) {
rspInfo = info;
cardStatus = card_status;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::supplyIccPinForAppResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::supplyIccPukForAppResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::changeIccPinForAppResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::changeIccPin2ForAppResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
int32_t /*remainingRetries*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getCurrentCallsResponse(
const RadioResponseInfo& info, const ::android::hardware::hidl_vec<Call>& /*calls*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::dialResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -94,72 +94,72 @@ Return<void> RadioResponse::getIMSIForAppResponse(const RadioResponseInfo& info,
const ::android::hardware::hidl_string& imsi) {
rspInfo = info;
this->imsi = imsi;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::hangupConnectionResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::hangupForegroundResumeBackgroundResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::conferenceResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::rejectCallResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getLastCallFailCauseResponse(
const RadioResponseInfo& info, const LastCallFailCauseInfo& /*failCauseInfo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getSignalStrengthResponse(const RadioResponseInfo& info,
const SignalStrength& /*sig_strength*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getVoiceRegistrationStateResponse(
const RadioResponseInfo& info, const VoiceRegStateResult& /*voiceRegResponse*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getDataRegistrationStateResponse(
const RadioResponseInfo& info, const DataRegStateResult& /*dataRegResponse*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const ::android::hardware::hidl_string& /*shortName*/,
const ::android::hardware::hidl_string& /*numeric*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setRadioPowerResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendDtmfResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const SendSmsResult& sms) {
rspInfo = info;
sendSmsResult = sms;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -196,14 +196,14 @@ Return<void> RadioResponse::sendSMSExpectMoreResponse(const RadioResponseInfo& i
const SendSmsResult& sms) {
rspInfo = info;
sendSmsResult = sms;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setupDataCallResponse(const RadioResponseInfo& info,
const SetupDataCallResult& /*dcResponse*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -211,32 +211,32 @@ Return<void> RadioResponse::iccIOForAppResponse(const RadioResponseInfo& info,
const IccIoResult& iccIo) {
rspInfo = info;
this->iccIoResult = iccIo;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendUssdResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::cancelPendingUssdResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getClirResponse(const RadioResponseInfo& info, int32_t /*n*/,
int32_t /*m*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setClirResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info, const ::android::hardware::hidl_vec<CallForwardInfo>&
/*callForwardInfos*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCallForwardResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getCallWaitingResponse(const RadioResponseInfo& info, bool /*enable*/,
int32_t /*serviceClass*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCallWaitingResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::acceptCallResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::deactivateDataCallResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getFacilityLockForAppResponse(const RadioResponseInfo& info,
int32_t /*response*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setFacilityLockForAppResponse(const RadioResponseInfo& info,
int32_t /*retry*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setBarringPasswordResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getNetworkSelectionModeResponse(const RadioResponseInfo& info,
bool /*manual*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setNetworkSelectionModeAutomaticResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setNetworkSelectionModeManualResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::startDtmfResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::stopDtmfResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getBasebandVersionResponse(
const RadioResponseInfo& info, const ::android::hardware::hidl_string& /*version*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::separateConnectionResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setMuteResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getMuteResponse(const RadioResponseInfo& info, bool /*enable*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getClipResponse(const RadioResponseInfo& info, ClipStatus /*status*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<SetupDataCallResult>& /*dcResponse*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setSuppServiceNotificationsResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index) {
rspInfo = info;
writeSmsToSimIndex = index;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::deleteSmsOnSimResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setBandModeResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<RadioBandMode>& /*bandModes*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendEnvelopeResponse(
const RadioResponseInfo& info, const ::android::hardware::hidl_string& /*commandResponse*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendTerminalResponseToSimResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::handleStkCallSetupRequestFromSimResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::explicitCallTransferResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setPreferredNetworkTypeResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getPreferredNetworkTypeResponse(const RadioResponseInfo& info,
PreferredNetworkType /*nw_type*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setLocationUpdatesResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
CdmaRoamingType /*type*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setTTYModeResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getTTYModeResponse(const RadioResponseInfo& info, TtyMode /*mode*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setPreferredVoicePrivacyResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getPreferredVoicePrivacyResponse(const RadioResponseInfo& info,
bool /*enable*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendCDMAFeatureCodeResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendBurstDtmfResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -541,13 +541,13 @@ Return<void> RadioResponse::sendCdmaSmsResponse(const RadioResponseInfo& info,
const SendSmsResult& sms) {
rspInfo = info;
sendSmsResult = sms;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setGsmBroadcastConfigResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setGsmBroadcastActivationResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCdmaBroadcastConfigResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCdmaBroadcastActivationResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const ::android::hardware::hidl_string& /*min*/,
const ::android::hardware::hidl_string& /*prl*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index) {
rspInfo = info;
writeSmsToRuimIndex = index;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::deleteSmsOnRuimResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const ::android::hardware::hidl_string& /*esn*/,
const ::android::hardware::hidl_string& /*meid*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::exitEmergencyCallbackModeResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -635,79 +635,79 @@ Return<void> RadioResponse::getSmscAddressResponse(const RadioResponseInfo& info
const ::android::hardware::hidl_string& smsc) {
rspInfo = info;
smscAddress = smsc;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setSmscAddressResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::reportSmsMemoryStatusResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::reportStkServiceIsRunningResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info,
CdmaSubscriptionSource /*source*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::requestIsimAuthenticationResponse(
const RadioResponseInfo& info, const ::android::hardware::hidl_string& /*response*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::acknowledgeIncomingGsmSmsWithPduResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
const IccIoResult& /*iccIo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getVoiceRadioTechnologyResponse(const RadioResponseInfo& info,
RadioTechnology /*rat*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getCellInfoListResponse(
const RadioResponseInfo& info, const ::android::hardware::hidl_vec<CellInfo>& /*cellInfo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setCellInfoListRateResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setInitialAttachApnResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -715,7 +715,7 @@ Return<void> RadioResponse::getImsRegistrationStateResponse(const RadioResponseI
bool /*isRegistered*/,
RadioTechnologyFamily /*ratFamily*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const SendSmsResult& sms) {
rspInfo = info;
sendSmsResult = sms;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -731,7 +731,7 @@ Return<void> RadioResponse::iccTransmitApduBasicChannelResponse(const RadioRespo
const IccIoResult& result) {
rspInfo = info;
this->iccIoResult = result;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) {
rspInfo = info;
this->channelId = channelId;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::iccCloseLogicalChannelResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -754,44 +754,44 @@ Return<void> RadioResponse::iccTransmitApduLogicalChannelResponse(const RadioRes
const IccIoResult& result) {
rspInfo = info;
this->iccIoResult = result;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::nvReadItemResponse(const RadioResponseInfo& info,
const ::android::hardware::hidl_string& /*result*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::nvWriteItemResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::nvWriteCdmaPrlResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::nvResetConfigResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setUiccSubscriptionResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setDataAllowedResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -807,68 +807,68 @@ Return<void> RadioResponse::requestIccSimAuthenticationResponse(const RadioRespo
const IccIoResult& result) {
rspInfo = info;
this->iccIoResult = result;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setDataProfileResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::requestShutdownResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getRadioCapabilityResponse(const RadioResponseInfo& info,
const RadioCapability& /*rc*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setRadioCapabilityResponse(const RadioResponseInfo& info,
const RadioCapability& /*rc*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::startLceServiceResponse(const RadioResponseInfo& info,
const LceStatusInfo& /*statusInfo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::stopLceServiceResponse(const RadioResponseInfo& info,
const LceStatusInfo& /*statusInfo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::pullLceDataResponse(const RadioResponseInfo& info,
const LceDataInfo& /*lceInfo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::getModemActivityInfoResponse(
const RadioResponseInfo& info, const ActivityStatsInfo& /*activityInfo*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setAllowedCarriersResponse(const RadioResponseInfo& info,
int32_t /*numAllowed*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
@@ -876,25 +876,25 @@ Return<void> RadioResponse::getAllowedCarriersResponse(const RadioResponseInfo&
bool /*allAllowed*/,
const CarrierRestrictions& /*carriers*/) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::sendDeviceStateResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setIndicationFilterResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
Return<void> RadioResponse::setSimCardPowerResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent.notify();
+ parent.notify(info.serial);
return Void();
}
index fdcc15c374e82233307f35486b2676bb4b59d788..cce69d5ff190c2bc3be7bf4ab4844349f0f8683e 100644 (file)
Return<void> SapCallback::connectResponse(int32_t token, SapConnectRsp /*sapConnectRsp*/,
int32_t /*maxMsgSize*/) {
sapResponseToken = token;
- parent.notify();
+ parent.notify(token);
return Void();
}
Return<void> SapCallback::disconnectResponse(int32_t token) {
sapResponseToken = token;
- parent.notify();
+ parent.notify(token);
return Void();
}
const ::android::hardware::hidl_vec<uint8_t>& /*apduRsp*/) {
sapResponseToken = token;
sapResultCode = resultCode;
- parent.notify();
+ parent.notify(token);
return Void();
}
const ::android::hardware::hidl_vec<uint8_t>& /*atr*/) {
sapResponseToken = token;
sapResultCode = resultCode;
- parent.notify();
+ parent.notify(token);
return Void();
}
Return<void> SapCallback::powerResponse(int32_t token, SapResultCode resultCode) {
sapResponseToken = token;
sapResultCode = resultCode;
- parent.notify();
+ parent.notify(token);
return Void();
}
Return<void> SapCallback::resetSimResponse(int32_t token, SapResultCode resultCode) {
sapResponseToken = token;
sapResultCode = resultCode;
- parent.notify();
+ parent.notify(token);
return Void();
}
int32_t /*cardReaderStatus*/) {
sapResponseToken = token;
sapResultCode = resultCode;
- parent.notify();
+ parent.notify(token);
return Void();
}
Return<void> SapCallback::transferProtocolResponse(int32_t token, SapResultCode resultCode) {
sapResponseToken = token;
sapResultCode = resultCode;
- parent.notify();
+ parent.notify(token);
return Void();
}
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp
index d0788ddeed93a271202fce1e0c05760c9b69cd5c..da78f410d103a8abafba5999fe3e8d723b6231b4 100644 (file)
* Test ISap.connectReq() for the response returned.
*/
TEST_F(SapHidlTest, connectReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
int32_t maxMsgSize = 100;
sap->connectReq(token, maxMsgSize);
* Test IRadio.disconnectReq() for the response returned
*/
TEST_F(SapHidlTest, disconnectReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
sap->disconnectReq(token);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.apduReq() for the response returned.
*/
TEST_F(SapHidlTest, apduReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
SapApduType sapApduType = SapApduType::APDU;
android::hardware::hidl_vec<uint8_t> command = {};
* Test IRadio.transferAtrReq() for the response returned.
*/
TEST_F(SapHidlTest, transferAtrReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
sap->transferAtrReq(token);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.powerReq() for the response returned.
*/
TEST_F(SapHidlTest, powerReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
bool state = true;
sap->powerReq(token, state);
* Test IRadio.resetSimReq() for the response returned.
*/
TEST_F(SapHidlTest, resetSimReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
sap->resetSimReq(token);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.transferCardReaderStatusReq() for the response returned.
*/
TEST_F(SapHidlTest, transferCardReaderStatusReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
sap->transferCardReaderStatusReq(token);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setTransferProtocolReq() for the response returned.
*/
TEST_F(SapHidlTest, setTransferProtocolReq) {
- int32_t token = GetRandomSerialNumber();
+ token = GetRandomSerialNumber();
SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0;
sap->setTransferProtocolReq(token, sapTransferProtocol);
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
index 772050548bccd52deca77fc2077cd9159e5d9bc4..88fdd7bc3852d76a2d9a5eeb13cc022721490074 100644 (file)
void SapHidlTest::TearDown() {}
-void SapHidlTest::notify() {
+void SapHidlTest::notify(int receivedToken) {
std::unique_lock<std::mutex> lock(mtx);
count++;
- cv.notify_one();
+ if (token == receivedToken) {
+ cv.notify_one();
}
+}
- std::cv_status SapHidlTest::wait() {
- std::unique_lock<std::mutex> lock(mtx);
+std::cv_status SapHidlTest::wait() {
+ std::unique_lock<std::mutex> lock(mtx);
- std::cv_status status = std::cv_status::no_timeout;
- auto now = std::chrono::system_clock::now();
- while (count == 0) {
- status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
- if (status == std::cv_status::timeout) {
- return status;
- }
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count == 0) {
+ status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) {
+ return status;
}
- count--;
- return status;
- }
\ No newline at end of file
+ }
+ count--;
+ return status;
+}
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_utils.h b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
index fb142b796fb21d48d53b6bb3a0444a73ae306546..8151b9d8037839b3093abbdd59e2e0d2a0f5d557 100644 (file)
virtual void TearDown() override;
/* Used as a mechanism to inform the test about data/event callback */
- void notify();
+ void notify(int receivedToken);
/* Test code calls this function to wait for response */
std::cv_status wait();
/* Sap Callback object */
sp<SapCallback> sapCb;
-};
\ No newline at end of file
+
+ /* Token for sap request */
+ int32_t token;
+};
diff --git a/radio/1.1/ISap.hal b/radio/1.1/ISap.hal
index edcf176aacdc2dad6ec0dbbbd1b88871cd4d411d..0cabccc1856e447925f913d14d4b6899b18b3c65 100644 (file)
--- a/radio/1.1/ISap.hal
+++ b/radio/1.1/ISap.hal
import @1.0::ISap;
-interface ISap extends @1.0::ISap {
- /**
- * Empty top level interface.
- */
-};
+/**
+ * Empty top level interface.
+ */
+interface ISap extends @1.0::ISap {};
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
index 17c2a837391d4f8da6ee4701f9fad208b72eb396..90077dcf61e28cedeea903f47ae9576e38f5340a 100644 (file)
* Test IRadio.setSimCardPower() for the response returned.
*/
TEST_F(RadioHidlTest_v1_1, setSimCardPower_1_1) {
- int serial = GetRandomSerialNumber();
+ /* Record the sim card state for the testing environment */
+ CardState cardStateForTest = cardStatus.cardState;
+ /* Test setSimCardPower power down */
+ serial = GetRandomSerialNumber();
radio_v1_1->setSimCardPower_1_1(serial, CardPowerState::POWER_DOWN);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_1->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_1->rspInfo.serial);
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_1->rspInfo.error,
+ {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
+ RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+ /* Wait some time for setting sim power down and then verify it */
+ updateSimCardStatus();
+ auto startTime = std::chrono::system_clock::now();
+ while (cardStatus.cardState != CardState::ABSENT &&
+ std::chrono::duration_cast<chrono::seconds>(std::chrono::system_clock::now() - startTime)
+ .count() < 80) {
+ /* Set 2 seconds as interval to check card status */
+ sleep(2);
+ updateSimCardStatus();
+ }
+ EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
- if (cardStatus.cardState == CardState::ABSENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_1->rspInfo.error,
- {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
- RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+ /* Test setSimCardPower power up */
+ serial = GetRandomSerialNumber();
+ radio_v1_1->setSimCardPower_1_1(serial, CardPowerState::POWER_UP);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_1->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_1->rspInfo.serial);
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_1->rspInfo.error,
+ {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
+ RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+
+ /**
+ * If the sim card status for the testing environment is PRESENT,
+ * verify if sim status is reset back.
+ */
+ if (cardStateForTest == CardState::PRESENT) {
+ /* Wait some time for resetting back to sim power on and then verify it */
+ updateSimCardStatus();
+ startTime = std::chrono::system_clock::now();
+ while (cardStatus.cardState != CardState::PRESENT &&
+ std::chrono::duration_cast<chrono::seconds>(std::chrono::system_clock::now() -
+ startTime)
+ .count() < 80) {
+ /* Set 2 seconds as interval to check card status */
+ sleep(2);
+ updateSimCardStatus();
+ }
+ EXPECT_EQ(CardState::PRESENT, cardStatus.cardState);
}
}
* Test IRadio.startNetworkScan() for the response returned.
*/
TEST_F(RadioHidlTest_v1_1, startNetworkScan) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
NetworkScanRequest request;
request.type = ScanType::ONE_SHOT;
* Test IRadio.startNetworkScan() for the response returned.
*/
TEST_F(RadioHidlTest_v1_1, startNetworkScan_InvalidArgument) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
NetworkScanRequest request;
request.type = ScanType::ONE_SHOT;
* Test IRadio.stopNetworkScan() for the response returned.
*/
TEST_F(RadioHidlTest_v1_1, stopNetworkScan) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio_v1_1->stopNetworkScan(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
* Test IRadio.setCarrierInfoForImsiEncryption() for the response returned.
*/
TEST_F(RadioHidlTest_v1_1, setCarrierInfoForImsiEncryption) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
ImsiEncryptionInfo imsiInfo;
imsiInfo.mcc = "310";
imsiInfo.mnc = "004";
}};
for (auto req = requests.begin(); req != requests.end(); req++) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio_v1_1->startKeepalive(serial, *req);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_1->rspInfo.type);
* Test IRadio.stopKeepalive() for the response returned.
*/
TEST_F(RadioHidlTest_v1_1, stopKeepalive) {
- int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
radio_v1_1->stopKeepalive(serial, 0xBAD);
EXPECT_EQ(std::cv_status::no_timeout, wait());
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_test.cpp b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
index 488da2d119338b50a0bf7a971172ff0952999b8b..e18d075b7a1ec50510137b6d1e14a3144f88aead 100644 (file)
radio_v1_1->setResponseFunctions(radioRsp_v1_1, radioInd_v1_1);
- int serial = GetRandomSerialNumber();
- radio_v1_1->getIccCardStatus(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
+ updateSimCardStatus();
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_1->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_1->rspInfo.serial);
EXPECT_EQ(RadioError::NONE, radioRsp_v1_1->rspInfo.error);
- /* Vts Testing with Sim Absent only. This needs to be removed later in P when sim present
- * scenarios will be tested. */
- EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
+ /* Enforce Vts Testing with Sim Status Present only. */
+ EXPECT_EQ(CardState::PRESENT, cardStatus.cardState);
}
-void RadioHidlTest_v1_1::notify() {
+void RadioHidlTest_v1_1::notify(int receivedSerial) {
std::unique_lock<std::mutex> lock(mtx);
- count++;
- cv.notify_one();
+ if (serial == receivedSerial) {
+ count++;
+ cv.notify_one();
+ }
}
std::cv_status RadioHidlTest_v1_1::wait(int sec) {
count--;
return status;
}
+
+void RadioHidlTest_v1_1::updateSimCardStatus() {
+ serial = GetRandomSerialNumber();
+ radio_v1_1->getIccCardStatus(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
\ No newline at end of file
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h b/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h
index a081ab978db3b86aca068f4630d4725f9c7bd1a4..3f5e559544423df736a1864fa760f353c1fe7eb9 100644 (file)
std::condition_variable cv;
int count;
+ /* Serial number for radio request */
+ int serial;
+
+ /* Update Sim Card Status */
+ void updateSimCardStatus();
+
public:
virtual void SetUp() override;
/* Used as a mechanism to inform the test about data/event callback */
- void notify();
+ void notify(int receivedSerial);
/* Test code calls this function to wait for response */
std::cv_status wait(int sec = TIMEOUT_PERIOD);
diff --git a/radio/1.1/vts/functional/radio_response.cpp b/radio/1.1/vts/functional/radio_response.cpp
index 400ef3c00138031ed6a7717b9dc7fddf7f0eee71..c2edde8b5c0c741936df80c50a0c25f04e571a38 100644 (file)
const CardStatus& card_status) {
rspInfo = info;
cardStatus = card_status;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_1::setCarrierInfoForImsiEncryptionResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_1::setSimCardPowerResponse_1_1(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_1::startNetworkScanResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_1::stopNetworkScanResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
@@ -687,12 +687,12 @@ Return<void> RadioResponse_v1_1::startKeepaliveResponse(const RadioResponseInfo&
const KeepaliveStatus& status) {
rspInfo = info;
keepaliveStatus = status;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_1::stopKeepaliveResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_1.notify();
+ parent_v1_1.notify(info.serial);
return Void();
}
diff --git a/radio/1.2/ISap.hal b/radio/1.2/ISap.hal
index 757027ce021868ce2222ef67424a902a59abbbcb..65f9b848b1af9d537ee96e2b394326c87cd3b102 100644 (file)
--- a/radio/1.2/ISap.hal
+++ b/radio/1.2/ISap.hal
import @1.1::ISap;
-interface ISap extends @1.1::ISap {
- /**
- * Empty top level interface.
- */
-};
+/**
+ * Empty top level interface.
+ */
+interface ISap extends @1.1::ISap {};
diff --git a/radio/1.2/default/Android.bp b/radio/1.2/default/Android.bp
--- /dev/null
@@ -0,0 +1,39 @@
+cc_binary {
+ name: "android.hardware.radio@1.2-radio-service",
+ init_rc: ["android.hardware.radio@1.2-radio-service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: [
+ "Radio.cpp",
+ "radio-service.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.radio@1.2",
+ "android.hardware.radio@1.0",
+ "android.hardware.radio@1.1",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.radio@1.2-sap-service",
+ init_rc: ["android.hardware.radio@1.2-sap-service.rc"],
+ relative_install_path: "hw",
+ vendor: true,
+ srcs: [
+ "Sap.cpp",
+ "sap-service.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.radio@1.2",
+ "android.hardware.radio@1.0",
+ "android.hardware.radio@1.1",
+ ],
+}
diff --git a/radio/1.2/default/Radio.cpp b/radio/1.2/default/Radio.cpp
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "Radio.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace V1_2 {
+namespace implementation {
+
+// Methods from ::android::hardware::radio::V1_0::IRadio follow.
+Return<void> Radio::setResponseFunctions(
+ const sp<::android::hardware::radio::V1_0::IRadioResponse>& radioResponse,
+ const sp<::android::hardware::radio::V1_0::IRadioIndication>& radioIndication) {
+ mRadioResponse = radioResponse;
+ mRadioIndication = radioIndication;
+ mRadioResponseV1_1 = ::android::hardware::radio::V1_1::IRadioResponse::castFrom(mRadioResponse)
+ .withDefault(nullptr);
+ mRadioIndicationV1_1 =
+ ::android::hardware::radio::V1_1::IRadioIndication::castFrom(mRadioIndication)
+ .withDefault(nullptr);
+ if (mRadioResponseV1_1 == nullptr || mRadioIndicationV1_1 == nullptr) {
+ mRadioResponseV1_1 = nullptr;
+ mRadioIndicationV1_1 = nullptr;
+ }
+ mRadioResponseV1_2 = ::android::hardware::radio::V1_2::IRadioResponse::castFrom(mRadioResponse)
+ .withDefault(nullptr);
+ mRadioIndicationV1_2 =
+ ::android::hardware::radio::V1_2::IRadioIndication::castFrom(mRadioIndication)
+ .withDefault(nullptr);
+ if (mRadioResponseV1_2 == nullptr || mRadioIndicationV1_2 == nullptr) {
+ mRadioResponseV1_2 = nullptr;
+ mRadioIndicationV1_2 = nullptr;
+ }
+ return Void();
+}
+
+Return<void> Radio::getIccCardStatus(int32_t serial) {
+ /**
+ * IRadio-defined request is called from the client and talk to the radio to get
+ * IRadioResponse-defined response or/and IRadioIndication-defined indication back to the
+ * client. This dummy implementation omits and replaces the design and implementation of vendor
+ * codes that needs to handle the receipt of the request and the return of the response from the
+ * radio; this just directly returns a dummy response back to the client.
+ */
+
+ ALOGD("Radio Request: getIccCardStatus is entering");
+
+ if (mRadioResponse != nullptr || mRadioResponseV1_1 != nullptr ||
+ mRadioResponseV1_2 != nullptr) {
+ // Dummy RadioResponseInfo as part of response to return in 1.0, 1.1 and 1.2
+ ::android::hardware::radio::V1_0::RadioResponseInfo info;
+ info.serial = serial;
+ info.type = ::android::hardware::radio::V1_0::RadioResponseType::SOLICITED;
+ info.error = ::android::hardware::radio::V1_0::RadioError::NONE;
+ /**
+ * In IRadio and IRadioResponse 1.2, getIccCardStatus can trigger radio to return
+ * getIccCardStatusResponse_1_2. In their 1.0 and 1.1, getIccCardStatus can trigger radio to
+ * return getIccCardStatusResponse.
+ */
+ if (mRadioResponseV1_2 != nullptr) {
+ // Dummy CardStatus as part of getIccCardStatusResponse_1_2 response to return
+ ::android::hardware::radio::V1_2::CardStatus card_status;
+ card_status.base.cardState = ::android::hardware::radio::V1_0::CardState::ABSENT;
+ card_status.base.gsmUmtsSubscriptionAppIndex = 0;
+ card_status.base.cdmaSubscriptionAppIndex = 0;
+ mRadioResponseV1_2->getIccCardStatusResponse_1_2(info, card_status);
+ ALOGD("Radio Response: getIccCardStatusResponse_1_2 is sent");
+ } else if (mRadioResponseV1_1 != nullptr) {
+ // Dummy CardStatus as part of getIccCardStatusResponse response to return
+ ::android::hardware::radio::V1_0::CardStatus card_status_V1_0;
+ card_status_V1_0.cardState = ::android::hardware::radio::V1_0::CardState::ABSENT;
+ card_status_V1_0.gsmUmtsSubscriptionAppIndex = 0;
+ card_status_V1_0.cdmaSubscriptionAppIndex = 0;
+ mRadioResponseV1_1->getIccCardStatusResponse(info, card_status_V1_0);
+ ALOGD("Radio Response: getIccCardStatusResponse is sent");
+ } else {
+ // Dummy CardStatus as part of getIccCardStatusResponse response to return
+ ::android::hardware::radio::V1_0::CardStatus card_status_V1_0;
+ card_status_V1_0.cardState = ::android::hardware::radio::V1_0::CardState::ABSENT;
+ card_status_V1_0.gsmUmtsSubscriptionAppIndex = 0;
+ card_status_V1_0.cdmaSubscriptionAppIndex = 0;
+ mRadioResponse->getIccCardStatusResponse(info, card_status_V1_0);
+ ALOGD("Radio Response: getIccCardStatusResponse is sent");
+ }
+ } else {
+ ALOGD("mRadioResponse, mRadioResponseV1_1, and mRadioResponseV1_2 are NULL");
+ }
+ return Void();
+}
+
+Return<void> Radio::supplyIccPinForApp(int32_t /* serial */, const hidl_string& /* pin */,
+ const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::supplyIccPukForApp(int32_t /* serial */, const hidl_string& /* puk */,
+ const hidl_string& /* pin */, const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::supplyIccPin2ForApp(int32_t /* serial */, const hidl_string& /* pin2 */,
+ const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::supplyIccPuk2ForApp(int32_t /* serial */, const hidl_string& /* puk2 */,
+ const hidl_string& /* pin2 */,
+ const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::changeIccPinForApp(int32_t /* serial */, const hidl_string& /* oldPin */,
+ const hidl_string& /* newPin */,
+ const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::changeIccPin2ForApp(int32_t /* serial */, const hidl_string& /* oldPin2 */,
+ const hidl_string& /* newPin2 */,
+ const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::supplyNetworkDepersonalization(int32_t /* serial */,
+ const hidl_string& /* netPin */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCurrentCalls(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::dial(int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::Dial& /* dialInfo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getImsiForApp(int32_t /* serial */, const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::hangup(int32_t /* serial */, int32_t /* gsmIndex */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::hangupWaitingOrBackground(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::hangupForegroundResumeBackground(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::switchWaitingOrHoldingAndActive(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::conference(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::rejectCall(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getLastCallFailCause(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getSignalStrength(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getVoiceRegistrationState(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getDataRegistrationState(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getOperator(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setRadioPower(int32_t /* serial */, bool /* on */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendDtmf(int32_t /* serial */, const hidl_string& /* s */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendSms(int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::GsmSmsMessage& /* message */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendSMSExpectMore(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::GsmSmsMessage& /* message */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setupDataCall(
+ int32_t /* serial */, ::android::hardware::radio::V1_0::RadioTechnology /* radioTechnology */,
+ const ::android::hardware::radio::V1_0::DataProfileInfo& /* dataProfileInfo */,
+ bool /* modemCognitive */, bool /* roamingAllowed */, bool /* isRoaming */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::iccIOForApp(int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::IccIo& /* iccIo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendUssd(int32_t /* serial */, const hidl_string& /* ussd */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::cancelPendingUssd(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getClir(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setClir(int32_t /* serial */, int32_t /* status */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCallForwardStatus(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::CallForwardInfo& /* callInfo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCallForward(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::CallForwardInfo& /* callInfo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCallWaiting(int32_t /* serial */, int32_t /* serviceClass */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCallWaiting(int32_t /* serial */, bool /* enable */,
+ int32_t /* serviceClass */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::acknowledgeLastIncomingGsmSms(
+ int32_t /* serial */, bool /* success */,
+ ::android::hardware::radio::V1_0::SmsAcknowledgeFailCause /* cause */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::acceptCall(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::deactivateDataCall(int32_t /* serial */, int32_t /* cid */,
+ bool /* reasonRadioShutDown */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getFacilityLockForApp(int32_t /* serial */, const hidl_string& /* facility */,
+ const hidl_string& /* password */,
+ int32_t /* serviceClass */,
+ const hidl_string& /* appId */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setFacilityLockForApp(int32_t /* serial */, const hidl_string& /* facility */,
+ bool /* lockState */, const hidl_string& /* password */,
+ int32_t /* serviceClass */,
+ const hidl_string& /* appId */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setBarringPassword(int32_t /* serial */, const hidl_string& /* facility */,
+ const hidl_string& /* oldPassword */,
+ const hidl_string& /* newPassword */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getNetworkSelectionMode(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setNetworkSelectionModeAutomatic(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setNetworkSelectionModeManual(int32_t /* serial */,
+ const hidl_string& /* operatorNumeric */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getAvailableNetworks(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::startDtmf(int32_t /* serial */, const hidl_string& /* s */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::stopDtmf(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getBasebandVersion(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::separateConnection(int32_t /* serial */, int32_t /* gsmIndex */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setMute(int32_t /* serial */, bool /* enable */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getMute(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getClip(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getDataCallList(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setSuppServiceNotifications(int32_t /* serial */, bool /* enable */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::writeSmsToSim(
+ int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::SmsWriteArgs& /* smsWriteArgs */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::deleteSmsOnSim(int32_t /* serial */, int32_t /* index */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setBandMode(int32_t /* serial */,
+ ::android::hardware::radio::V1_0::RadioBandMode /* mode */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getAvailableBandModes(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendEnvelope(int32_t /* serial */, const hidl_string& /* command */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendTerminalResponseToSim(int32_t /* serial */,
+ const hidl_string& /* commandResponse */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::handleStkCallSetupRequestFromSim(int32_t /* serial */, bool /* accept */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::explicitCallTransfer(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setPreferredNetworkType(
+ int32_t /* serial */, ::android::hardware::radio::V1_0::PreferredNetworkType /* nwType */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getPreferredNetworkType(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getNeighboringCids(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setLocationUpdates(int32_t /* serial */, bool /* enable */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCdmaSubscriptionSource(
+ int32_t /* serial */, ::android::hardware::radio::V1_0::CdmaSubscriptionSource /* cdmaSub */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCdmaRoamingPreference(
+ int32_t /* serial */, ::android::hardware::radio::V1_0::CdmaRoamingType /* type */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCdmaRoamingPreference(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setTTYMode(int32_t /* serial */,
+ ::android::hardware::radio::V1_0::TtyMode /* mode */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getTTYMode(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setPreferredVoicePrivacy(int32_t /* serial */, bool /* enable */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getPreferredVoicePrivacy(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendCDMAFeatureCode(int32_t /* serial */,
+ const hidl_string& /* featureCode */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendBurstDtmf(int32_t /* serial */, const hidl_string& /* dtmf*/,
+ int32_t /*on*/, int32_t /*off */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendCdmaSms(int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::CdmaSmsMessage& /* sms */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::acknowledgeLastIncomingCdmaSms(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::CdmaSmsAck& /* smsAck */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getGsmBroadcastConfig(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setGsmBroadcastConfig(
+ int32_t /* serial */,
+ const hidl_vec<::android::hardware::radio::V1_0::GsmBroadcastSmsConfigInfo>& /* configInfo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setGsmBroadcastActivation(int32_t /* serial */, bool /* activate */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCdmaBroadcastConfig(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCdmaBroadcastConfig(
+ int32_t /* serial */,
+ const hidl_vec<
+ ::android::hardware::radio::V1_0::CdmaBroadcastSmsConfigInfo>& /* configInfo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCdmaBroadcastActivation(int32_t /* serial */, bool /* activate */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCDMASubscription(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::writeSmsToRuim(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::CdmaSmsWriteArgs& /* cdmaSms */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::deleteSmsOnRuim(int32_t /* serial */, int32_t /* index */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getDeviceIdentity(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::exitEmergencyCallbackMode(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getSmscAddress(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setSmscAddress(int32_t /* serial */, const hidl_string& /* smsc */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::reportSmsMemoryStatus(int32_t /* serial */, bool /* available */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::reportStkServiceIsRunning(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCdmaSubscriptionSource(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::requestIsimAuthentication(int32_t /* serial */,
+ const hidl_string& /* challenge */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::acknowledgeIncomingGsmSmsWithPdu(int32_t /* serial */, bool /* success */,
+ const hidl_string& /* ackPdu */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendEnvelopeWithStatus(int32_t /* serial */,
+ const hidl_string& /* contents */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getVoiceRadioTechnology(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getCellInfoList(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setCellInfoListRate(int32_t /* serial */, int32_t /*rate */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setInitialAttachApn(
+ int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::DataProfileInfo& /* dataProfileInfo */,
+ bool /* modemCognitive */, bool /* isRoaming */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getImsRegistrationState(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendImsSms(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::ImsSmsMessage& /* message */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::iccTransmitApduBasicChannel(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::SimApdu& /* message */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::iccOpenLogicalChannel(int32_t /* serial */, const hidl_string& /* aid*/,
+ int32_t /*p2 */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::iccCloseLogicalChannel(int32_t /* serial */, int32_t /* channelId */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::iccTransmitApduLogicalChannel(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::SimApdu& /* message */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::nvReadItem(int32_t /* serial */,
+ ::android::hardware::radio::V1_0::NvItem /* itemId */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::nvWriteItem(int32_t /* serial */,
+ const ::android::hardware::radio::V1_0::NvWriteItem& /* item */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::nvWriteCdmaPrl(int32_t /* serial */, const hidl_vec<uint8_t>& /* prl */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::nvResetConfig(int32_t /* serial */,
+ ::android::hardware::radio::V1_0::ResetNvType /* resetType */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setUiccSubscription(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::SelectUiccSub& /* uiccSub */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setDataAllowed(int32_t /* serial */, bool /* allow */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getHardwareConfig(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::requestIccSimAuthentication(int32_t /* serial */, int32_t /* authContext */,
+ const hidl_string& /* authData */,
+ const hidl_string& /* aid */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setDataProfile(
+ int32_t /* serial */,
+ const hidl_vec<::android::hardware::radio::V1_0::DataProfileInfo>& /* profiles */,
+ bool /* isRoaming */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::requestShutdown(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getRadioCapability(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setRadioCapability(
+ int32_t /* serial */, const ::android::hardware::radio::V1_0::RadioCapability& /* rc */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::startLceService(int32_t /* serial */, int32_t /* reportInterval */,
+ bool /* pullMode */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::stopLceService(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::pullLceData(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getModemActivityInfo(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setAllowedCarriers(
+ int32_t /* serial */, bool /* allAllowed */,
+ const ::android::hardware::radio::V1_0::CarrierRestrictions& /* carriers */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::getAllowedCarriers(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::sendDeviceState(
+ int32_t /* serial */, ::android::hardware::radio::V1_0::DeviceStateType /* deviceStateType */,
+ bool /* state */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setIndicationFilter(int32_t /* serial */,
+ hidl_bitfield<IndicationFilter> /* indicationFilter */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setSimCardPower(int32_t /* serial */, bool /* powerUp */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::responseAcknowledgement() {
+ // TODO implement
+ return Void();
+}
+
+// Methods from ::android::hardware::radio::V1_1::IRadio follow.
+Return<void> Radio::setCarrierInfoForImsiEncryption(
+ int32_t /* serial */,
+ const ::android::hardware::radio::V1_1::ImsiEncryptionInfo& /* imsiEncryptionInfo */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setSimCardPower_1_1(
+ int32_t /* serial */, ::android::hardware::radio::V1_1::CardPowerState /* powerUp */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::startNetworkScan(
+ int32_t /* serial */,
+ const ::android::hardware::radio::V1_1::NetworkScanRequest& /* request */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::stopNetworkScan(int32_t /* serial */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::startKeepalive(
+ int32_t /* serial */,
+ const ::android::hardware::radio::V1_1::KeepaliveRequest& /* keepalive */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::stopKeepalive(int32_t /* serial */, int32_t /* sessionHandle */) {
+ // TODO implement
+ return Void();
+}
+
+// Methods from ::android::hardware::radio::V1_2::IRadio follow.
+Return<void> Radio::startNetworkScan_1_2(
+ int32_t /* serial */,
+ const ::android::hardware::radio::V1_2::NetworkScanRequest& /* request */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setIndicationFilter_1_2(
+ int32_t /* serial */, hidl_bitfield<IndicationFilter> /* indicationFilter */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setSignalStrengthReportingCriteria(
+ int32_t /* serial */, int32_t /*hysteresisMs*/, int32_t /*hysteresisDb */,
+ const hidl_vec<int32_t>& /* thresholdsDbm */,
+ ::android::hardware::radio::V1_2::AccessNetwork /* accessNetwork */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setLinkCapacityReportingCriteria(
+ int32_t /* serial */, int32_t /*hysteresisMs*/, int32_t /*hysteresisDlKbps*/,
+ int32_t /*hysteresisUlKbps */, const hidl_vec<int32_t>& /* thresholdsDownlinkKbps */,
+ const hidl_vec<int32_t>& /* thresholdsUplinkKbps */,
+ ::android::hardware::radio::V1_2::AccessNetwork /* accessNetwork */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::setupDataCall_1_2(
+ int32_t /* serial */, ::android::hardware::radio::V1_2::AccessNetwork /* accessNetwork */,
+ const ::android::hardware::radio::V1_0::DataProfileInfo& /* dataProfileInfo */,
+ bool /* modemCognitive */, bool /* roamingAllowed */, bool /* isRoaming */,
+ ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
+ const hidl_vec<hidl_string>& /* addresses */, const hidl_vec<hidl_string>& /* dnses */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Radio::deactivateDataCall_1_2(
+ int32_t /* serial */, int32_t /* cid */,
+ ::android::hardware::radio::V1_2::DataRequestReason /* reason */) {
+ // TODO implement
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace radio
+} // namespace hardware
+} // namespace android
diff --git a/radio/1.2/default/Radio.h b/radio/1.2/default/Radio.h
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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_RADIO_V1_2_RADIO_H
+#define ANDROID_HARDWARE_RADIO_V1_2_RADIO_H
+
+#include <android/hardware/radio/1.2/IRadio.h>
+#include <android/hardware/radio/1.2/IRadioIndication.h>
+#include <android/hardware/radio/1.2/IRadioResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Radio : public IRadio {
+ sp<::android::hardware::radio::V1_0::IRadioResponse> mRadioResponse;
+ sp<::android::hardware::radio::V1_0::IRadioIndication> mRadioIndication;
+ sp<::android::hardware::radio::V1_1::IRadioResponse> mRadioResponseV1_1;
+ sp<::android::hardware::radio::V1_1::IRadioIndication> mRadioIndicationV1_1;
+ sp<::android::hardware::radio::V1_2::IRadioResponse> mRadioResponseV1_2;
+ sp<::android::hardware::radio::V1_2::IRadioIndication> mRadioIndicationV1_2;
+
+ // Methods from ::android::hardware::radio::V1_0::IRadio follow.
+ Return<void> setResponseFunctions(
+ const sp<::android::hardware::radio::V1_0::IRadioResponse>& radioResponse,
+ const sp<::android::hardware::radio::V1_0::IRadioIndication>& radioIndication) override;
+ Return<void> getIccCardStatus(int32_t serial) override;
+ Return<void> supplyIccPinForApp(int32_t serial, const hidl_string& pin,
+ const hidl_string& aid) override;
+ Return<void> supplyIccPukForApp(int32_t serial, const hidl_string& puk, const hidl_string& pin,
+ const hidl_string& aid) override;
+ Return<void> supplyIccPin2ForApp(int32_t serial, const hidl_string& pin2,
+ const hidl_string& aid) override;
+ Return<void> supplyIccPuk2ForApp(int32_t serial, const hidl_string& puk2,
+ const hidl_string& pin2, const hidl_string& aid) override;
+ Return<void> changeIccPinForApp(int32_t serial, const hidl_string& oldPin,
+ const hidl_string& newPin, const hidl_string& aid) override;
+ Return<void> changeIccPin2ForApp(int32_t serial, const hidl_string& oldPin2,
+ const hidl_string& newPin2, const hidl_string& aid) override;
+ Return<void> supplyNetworkDepersonalization(int32_t serial, const hidl_string& netPin) override;
+ Return<void> getCurrentCalls(int32_t serial) override;
+ Return<void> dial(int32_t serial,
+ const ::android::hardware::radio::V1_0::Dial& dialInfo) override;
+ Return<void> getImsiForApp(int32_t serial, const hidl_string& aid) override;
+ Return<void> hangup(int32_t serial, int32_t gsmIndex) override;
+ Return<void> hangupWaitingOrBackground(int32_t serial) override;
+ Return<void> hangupForegroundResumeBackground(int32_t serial) override;
+ Return<void> switchWaitingOrHoldingAndActive(int32_t serial) override;
+ Return<void> conference(int32_t serial) override;
+ Return<void> rejectCall(int32_t serial) override;
+ Return<void> getLastCallFailCause(int32_t serial) override;
+ Return<void> getSignalStrength(int32_t serial) override;
+ Return<void> getVoiceRegistrationState(int32_t serial) override;
+ Return<void> getDataRegistrationState(int32_t serial) override;
+ Return<void> getOperator(int32_t serial) override;
+ Return<void> setRadioPower(int32_t serial, bool on) override;
+ Return<void> sendDtmf(int32_t serial, const hidl_string& s) override;
+ Return<void> sendSms(int32_t serial,
+ const ::android::hardware::radio::V1_0::GsmSmsMessage& message) override;
+ Return<void> sendSMSExpectMore(
+ int32_t serial, const ::android::hardware::radio::V1_0::GsmSmsMessage& message) override;
+ Return<void> setupDataCall(
+ int32_t serial, ::android::hardware::radio::V1_0::RadioTechnology radioTechnology,
+ const ::android::hardware::radio::V1_0::DataProfileInfo& dataProfileInfo,
+ bool modemCognitive, bool roamingAllowed, bool isRoaming) override;
+ Return<void> iccIOForApp(int32_t serial,
+ const ::android::hardware::radio::V1_0::IccIo& iccIo) override;
+ Return<void> sendUssd(int32_t serial, const hidl_string& ussd) override;
+ Return<void> cancelPendingUssd(int32_t serial) override;
+ Return<void> getClir(int32_t serial) override;
+ Return<void> setClir(int32_t serial, int32_t status) override;
+ Return<void> getCallForwardStatus(
+ int32_t serial, const ::android::hardware::radio::V1_0::CallForwardInfo& callInfo) override;
+ Return<void> setCallForward(
+ int32_t serial, const ::android::hardware::radio::V1_0::CallForwardInfo& callInfo) override;
+ Return<void> getCallWaiting(int32_t serial, int32_t serviceClass) override;
+ Return<void> setCallWaiting(int32_t serial, bool enable, int32_t serviceClass) override;
+ Return<void> acknowledgeLastIncomingGsmSms(
+ int32_t serial, bool success,
+ ::android::hardware::radio::V1_0::SmsAcknowledgeFailCause cause) override;
+ Return<void> acceptCall(int32_t serial) override;
+ Return<void> deactivateDataCall(int32_t serial, int32_t cid, bool reasonRadioShutDown) override;
+ Return<void> getFacilityLockForApp(int32_t serial, const hidl_string& facility,
+ const hidl_string& password, int32_t serviceClass,
+ const hidl_string& appId) override;
+ Return<void> setFacilityLockForApp(int32_t serial, const hidl_string& facility, bool lockState,
+ const hidl_string& password, int32_t serviceClass,
+ const hidl_string& appId) override;
+ Return<void> setBarringPassword(int32_t serial, const hidl_string& facility,
+ const hidl_string& oldPassword,
+ const hidl_string& newPassword) override;
+ Return<void> getNetworkSelectionMode(int32_t serial) override;
+ Return<void> setNetworkSelectionModeAutomatic(int32_t serial) override;
+ Return<void> setNetworkSelectionModeManual(int32_t serial,
+ const hidl_string& operatorNumeric) override;
+ Return<void> getAvailableNetworks(int32_t serial) override;
+ Return<void> startDtmf(int32_t serial, const hidl_string& s) override;
+ Return<void> stopDtmf(int32_t serial) override;
+ Return<void> getBasebandVersion(int32_t serial) override;
+ Return<void> separateConnection(int32_t serial, int32_t gsmIndex) override;
+ Return<void> setMute(int32_t serial, bool enable) override;
+ Return<void> getMute(int32_t serial) override;
+ Return<void> getClip(int32_t serial) override;
+ Return<void> getDataCallList(int32_t serial) override;
+ Return<void> setSuppServiceNotifications(int32_t serial, bool enable) override;
+ Return<void> writeSmsToSim(
+ int32_t serial,
+ const ::android::hardware::radio::V1_0::SmsWriteArgs& smsWriteArgs) override;
+ Return<void> deleteSmsOnSim(int32_t serial, int32_t index) override;
+ Return<void> setBandMode(int32_t serial,
+ ::android::hardware::radio::V1_0::RadioBandMode mode) override;
+ Return<void> getAvailableBandModes(int32_t serial) override;
+ Return<void> sendEnvelope(int32_t serial, const hidl_string& command) override;
+ Return<void> sendTerminalResponseToSim(int32_t serial,
+ const hidl_string& commandResponse) override;
+ Return<void> handleStkCallSetupRequestFromSim(int32_t serial, bool accept) override;
+ Return<void> explicitCallTransfer(int32_t serial) override;
+ Return<void> setPreferredNetworkType(
+ int32_t serial, ::android::hardware::radio::V1_0::PreferredNetworkType nwType) override;
+ Return<void> getPreferredNetworkType(int32_t serial) override;
+ Return<void> getNeighboringCids(int32_t serial) override;
+ Return<void> setLocationUpdates(int32_t serial, bool enable) override;
+ Return<void> setCdmaSubscriptionSource(
+ int32_t serial, ::android::hardware::radio::V1_0::CdmaSubscriptionSource cdmaSub) override;
+ Return<void> setCdmaRoamingPreference(
+ int32_t serial, ::android::hardware::radio::V1_0::CdmaRoamingType type) override;
+ Return<void> getCdmaRoamingPreference(int32_t serial) override;
+ Return<void> setTTYMode(int32_t serial,
+ ::android::hardware::radio::V1_0::TtyMode mode) override;
+ Return<void> getTTYMode(int32_t serial) override;
+ Return<void> setPreferredVoicePrivacy(int32_t serial, bool enable) override;
+ Return<void> getPreferredVoicePrivacy(int32_t serial) override;
+ Return<void> sendCDMAFeatureCode(int32_t serial, const hidl_string& featureCode) override;
+ Return<void> sendBurstDtmf(int32_t serial, const hidl_string& dtmf, int32_t on,
+ int32_t off) override;
+ Return<void> sendCdmaSms(int32_t serial,
+ const ::android::hardware::radio::V1_0::CdmaSmsMessage& sms) override;
+ Return<void> acknowledgeLastIncomingCdmaSms(
+ int32_t serial, const ::android::hardware::radio::V1_0::CdmaSmsAck& smsAck) override;
+ Return<void> getGsmBroadcastConfig(int32_t serial) override;
+ Return<void> setGsmBroadcastConfig(
+ int32_t serial,
+ const hidl_vec<::android::hardware::radio::V1_0::GsmBroadcastSmsConfigInfo>& configInfo)
+ override;
+ Return<void> setGsmBroadcastActivation(int32_t serial, bool activate) override;
+ Return<void> getCdmaBroadcastConfig(int32_t serial) override;
+ Return<void> setCdmaBroadcastConfig(
+ int32_t serial,
+ const hidl_vec<::android::hardware::radio::V1_0::CdmaBroadcastSmsConfigInfo>& configInfo)
+ override;
+ Return<void> setCdmaBroadcastActivation(int32_t serial, bool activate) override;
+ Return<void> getCDMASubscription(int32_t serial) override;
+ Return<void> writeSmsToRuim(
+ int32_t serial, const ::android::hardware::radio::V1_0::CdmaSmsWriteArgs& cdmaSms) override;
+ Return<void> deleteSmsOnRuim(int32_t serial, int32_t index) override;
+ Return<void> getDeviceIdentity(int32_t serial) override;
+ Return<void> exitEmergencyCallbackMode(int32_t serial) override;
+ Return<void> getSmscAddress(int32_t serial) override;
+ Return<void> setSmscAddress(int32_t serial, const hidl_string& smsc) override;
+ Return<void> reportSmsMemoryStatus(int32_t serial, bool available) override;
+ Return<void> reportStkServiceIsRunning(int32_t serial) override;
+ Return<void> getCdmaSubscriptionSource(int32_t serial) override;
+ Return<void> requestIsimAuthentication(int32_t serial, const hidl_string& challenge) override;
+ Return<void> acknowledgeIncomingGsmSmsWithPdu(int32_t serial, bool success,
+ const hidl_string& ackPdu) override;
+ Return<void> sendEnvelopeWithStatus(int32_t serial, const hidl_string& contents) override;
+ Return<void> getVoiceRadioTechnology(int32_t serial) override;
+ Return<void> getCellInfoList(int32_t serial) override;
+ Return<void> setCellInfoListRate(int32_t serial, int32_t rate) override;
+ Return<void> setInitialAttachApn(
+ int32_t serial, const ::android::hardware::radio::V1_0::DataProfileInfo& dataProfileInfo,
+ bool modemCognitive, bool isRoaming) override;
+ Return<void> getImsRegistrationState(int32_t serial) override;
+ Return<void> sendImsSms(
+ int32_t serial, const ::android::hardware::radio::V1_0::ImsSmsMessage& message) override;
+ Return<void> iccTransmitApduBasicChannel(
+ int32_t serial, const ::android::hardware::radio::V1_0::SimApdu& message) override;
+ Return<void> iccOpenLogicalChannel(int32_t serial, const hidl_string& aid, int32_t p2) override;
+ Return<void> iccCloseLogicalChannel(int32_t serial, int32_t channelId) override;
+ Return<void> iccTransmitApduLogicalChannel(
+ int32_t serial, const ::android::hardware::radio::V1_0::SimApdu& message) override;
+ Return<void> nvReadItem(int32_t serial,
+ ::android::hardware::radio::V1_0::NvItem itemId) override;
+ Return<void> nvWriteItem(int32_t serial,
+ const ::android::hardware::radio::V1_0::NvWriteItem& item) override;
+ Return<void> nvWriteCdmaPrl(int32_t serial, const hidl_vec<uint8_t>& prl) override;
+ Return<void> nvResetConfig(int32_t serial,
+ ::android::hardware::radio::V1_0::ResetNvType resetType) override;
+ Return<void> setUiccSubscription(
+ int32_t serial, const ::android::hardware::radio::V1_0::SelectUiccSub& uiccSub) override;
+ Return<void> setDataAllowed(int32_t serial, bool allow) override;
+ Return<void> getHardwareConfig(int32_t serial) override;
+ Return<void> requestIccSimAuthentication(int32_t serial, int32_t authContext,
+ const hidl_string& authData,
+ const hidl_string& aid) override;
+ Return<void> setDataProfile(
+ int32_t serial, const hidl_vec<::android::hardware::radio::V1_0::DataProfileInfo>& profiles,
+ bool isRoaming) override;
+ Return<void> requestShutdown(int32_t serial) override;
+ Return<void> getRadioCapability(int32_t serial) override;
+ Return<void> setRadioCapability(
+ int32_t serial, const ::android::hardware::radio::V1_0::RadioCapability& rc) override;
+ Return<void> startLceService(int32_t serial, int32_t reportInterval, bool pullMode) override;
+ Return<void> stopLceService(int32_t serial) override;
+ Return<void> pullLceData(int32_t serial) override;
+ Return<void> getModemActivityInfo(int32_t serial) override;
+ Return<void> setAllowedCarriers(
+ int32_t serial, bool allAllowed,
+ const ::android::hardware::radio::V1_0::CarrierRestrictions& carriers) override;
+ Return<void> getAllowedCarriers(int32_t serial) override;
+ Return<void> sendDeviceState(int32_t serial,
+ ::android::hardware::radio::V1_0::DeviceStateType deviceStateType,
+ bool state) override;
+ Return<void> setIndicationFilter(int32_t serial,
+ hidl_bitfield<IndicationFilter> indicationFilter) override;
+ Return<void> setSimCardPower(int32_t serial, bool powerUp) override;
+ Return<void> responseAcknowledgement() override;
+
+ // Methods from ::android::hardware::radio::V1_1::IRadio follow.
+ Return<void> setCarrierInfoForImsiEncryption(
+ int32_t serial,
+ const ::android::hardware::radio::V1_1::ImsiEncryptionInfo& imsiEncryptionInfo) override;
+ Return<void> setSimCardPower_1_1(
+ int32_t serial, ::android::hardware::radio::V1_1::CardPowerState powerUp) override;
+ Return<void> startNetworkScan(
+ int32_t serial,
+ const ::android::hardware::radio::V1_1::NetworkScanRequest& request) override;
+ Return<void> stopNetworkScan(int32_t serial) override;
+ Return<void> startKeepalive(
+ int32_t serial,
+ const ::android::hardware::radio::V1_1::KeepaliveRequest& keepalive) override;
+ Return<void> stopKeepalive(int32_t serial, int32_t sessionHandle) override;
+
+ // Methods from ::android::hardware::radio::V1_2::IRadio follow.
+ Return<void> startNetworkScan_1_2(
+ int32_t serial,
+ const ::android::hardware::radio::V1_2::NetworkScanRequest& request) override;
+ Return<void> setIndicationFilter_1_2(int32_t serial,
+ hidl_bitfield<IndicationFilter> indicationFilter) override;
+ Return<void> setSignalStrengthReportingCriteria(
+ int32_t serial, int32_t hysteresisMs, int32_t hysteresisDb,
+ const hidl_vec<int32_t>& thresholdsDbm,
+ ::android::hardware::radio::V1_2::AccessNetwork accessNetwork) override;
+ Return<void> setLinkCapacityReportingCriteria(
+ int32_t serial, int32_t hysteresisMs, int32_t hysteresisDlKbps, int32_t hysteresisUlKbps,
+ const hidl_vec<int32_t>& thresholdsDownlinkKbps,
+ const hidl_vec<int32_t>& thresholdsUplinkKbps,
+ ::android::hardware::radio::V1_2::AccessNetwork accessNetwork) override;
+ Return<void> setupDataCall_1_2(
+ int32_t serial, ::android::hardware::radio::V1_2::AccessNetwork accessNetwork,
+ const ::android::hardware::radio::V1_0::DataProfileInfo& dataProfileInfo,
+ bool modemCognitive, bool roamingAllowed, bool isRoaming,
+ ::android::hardware::radio::V1_2::DataRequestReason reason,
+ const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses) override;
+ Return<void> deactivateDataCall_1_2(
+ int32_t serial, int32_t cid,
+ ::android::hardware::radio::V1_2::DataRequestReason reason) override;
+};
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace radio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_RADIO_V1_2_RADIO_H
diff --git a/radio/1.2/default/Sap.cpp b/radio/1.2/default/Sap.cpp
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "Sap.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace V1_2 {
+namespace implementation {
+
+// Methods from ::android::hardware::radio::V1_0::ISap follow.
+Return<void> Sap::setCallback(
+ const sp<::android::hardware::radio::V1_0::ISapCallback>& sapCallback) {
+ mSapCallback = sapCallback;
+ return Void();
+}
+
+Return<void> Sap::connectReq(int32_t /* token */, int32_t /* maxMsgSize */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::disconnectReq(int32_t /* token */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::apduReq(int32_t /* token */,
+ ::android::hardware::radio::V1_0::SapApduType /* type */,
+ const hidl_vec<uint8_t>& /* command */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::transferAtrReq(int32_t /* token */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::powerReq(int32_t /* token */, bool /* state */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::resetSimReq(int32_t /* token */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::transferCardReaderStatusReq(int32_t /* token */) {
+ // TODO implement
+ return Void();
+}
+
+Return<void> Sap::setTransferProtocolReq(
+ int32_t /* token */,
+ ::android::hardware::radio::V1_0::SapTransferProtocol /* transferProtocol */) {
+ // TODO implement
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace radio
+} // namespace hardware
+} // namespace android
diff --git a/radio/1.2/default/Sap.h b/radio/1.2/default/Sap.h
--- /dev/null
+++ b/radio/1.2/default/Sap.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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_RADIO_V1_2_SAP_H
+#define ANDROID_HARDWARE_RADIO_V1_2_SAP_H
+
+#include <android/hardware/radio/1.2/ISap.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Sap : public ISap {
+ sp<::android::hardware::radio::V1_0::ISapCallback> mSapCallback;
+ // Methods from ::android::hardware::radio::V1_0::ISap follow.
+ Return<void> setCallback(
+ const sp<::android::hardware::radio::V1_0::ISapCallback>& sapCallback) override;
+ Return<void> connectReq(int32_t token, int32_t maxMsgSize) override;
+ Return<void> disconnectReq(int32_t token) override;
+ Return<void> apduReq(int32_t token, ::android::hardware::radio::V1_0::SapApduType type,
+ const hidl_vec<uint8_t>& command) override;
+ Return<void> transferAtrReq(int32_t token) override;
+ Return<void> powerReq(int32_t token, bool state) override;
+ Return<void> resetSimReq(int32_t token) override;
+ Return<void> transferCardReaderStatusReq(int32_t token) override;
+ Return<void> setTransferProtocolReq(
+ int32_t token,
+ ::android::hardware::radio::V1_0::SapTransferProtocol transferProtocol) override;
+};
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace radio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_RADIO_V1_2_SAP_H
diff --git a/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc b/radio/1.2/default/android.hardware.radio@1.2-radio-service.rc
--- /dev/null
@@ -0,0 +1,4 @@
+service vendor.radio-1-2 /vendor/bin/hw/android.hardware.radio@1.2-radio-service
+ class hal
+ user system
+ group system
diff --git a/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc b/radio/1.2/default/android.hardware.radio@1.2-sap-service.rc
--- /dev/null
@@ -0,0 +1,4 @@
+service vendor.sap-1-2 /vendor/bin/hw/android.hardware.radio@1.2-sap-service
+ class hal
+ user system
+ group system
diff --git a/radio/1.2/default/radio-service.cpp b/radio/1.2/default/radio-service.cpp
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "android.hardware.radio@1.2-radio-service"
+
+#include <android/hardware/radio/1.2/IRadio.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Radio.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::radio::V1_2::IRadio;
+using android::hardware::radio::V1_2::implementation::Radio;
+using android::sp;
+using android::status_t;
+using android::OK;
+
+int main() {
+ configureRpcThreadpool(1, true);
+
+ sp<IRadio> radio = new Radio;
+ status_t status = radio->registerAsService();
+ ALOGW_IF(status != OK, "Could not register IRadio v1.2");
+ ALOGD("Default service is ready.");
+
+ joinRpcThreadpool();
+ return 1;
+}
\ No newline at end of file
diff --git a/radio/1.2/default/sap-service.cpp b/radio/1.2/default/sap-service.cpp
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "android.hardware.radio@1.2-sap-service"
+
+#include <android/hardware/radio/1.2/ISap.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Sap.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::radio::V1_2::ISap;
+using android::hardware::radio::V1_2::implementation::Sap;
+using android::sp;
+using android::status_t;
+using android::OK;
+
+int main() {
+ configureRpcThreadpool(1, true);
+
+ sp<ISap> sap = new Sap;
+ status_t status = sap->registerAsService();
+ ALOGW_IF(status != OK, "Could not register ISap v1.2");
+ ALOGD("Default service is ready.");
+
+ joinRpcThreadpool();
+ return 1;
+}
\ No newline at end of file
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
index ee130f8544051f65c0e6dd6217f8192017a1d74e..9284fd8fae7196e74b89e8fafa184058fac73ab9 100644 (file)
* Test IRadio.startNetworkScan() for the response returned.
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
- .type = ScanType::ONE_SHOT,
- .interval = 60,
- .specifiers = {specifier}};
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
+ .type = ScanType::ONE_SHOT, .interval = 60, .specifiers = {specifier}};
Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
ASSERT_OK(res);
EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::SIM_ABSENT}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::NONE}));
}
}
* Test IRadio.startNetworkScan() with invalid specifier.
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidArgument) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
- V1_2::NetworkScanRequest request = {
- .type = ScanType::ONE_SHOT,
- .interval = 60};
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {.type = ScanType::ONE_SHOT,
+ .interval = 60};
Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
ASSERT_OK(res);
ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with invalid interval (lower boundary).
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval1) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 4,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with invalid interval (upper boundary).
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidInterval2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 301,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with invalid max search time (lower boundary).
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime1) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with invalid max search time (upper boundary).
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidMaxSearchTime2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with invalid periodicity (lower boundary).
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity1) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with invalid periodicity (upper boundary).
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_InvalidPeriodicity2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(
CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
* Test IRadio.startNetworkScan() with valid periodicity
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_GoodRequest1) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::NONE}));
}
}
* Test IRadio.startNetworkScan() with valid periodicity and plmns
*/
TEST_F(RadioHidlTest_v1_2, startNetworkScan_GoodRequest2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
RadioAccessSpecifier specifier = {
.radioAccessNetwork = RadioAccessNetworks::GERAN,
.geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
.channels = {1,2}};
- V1_2::NetworkScanRequest request = {
+ ::android::hardware::radio::V1_2::NetworkScanRequest request = {
.type = ScanType::ONE_SHOT,
.interval = 60,
.specifiers = {specifier},
ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
toString(radioRsp_v1_2->rspInfo.error).c_str());
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error, {RadioError::NONE}));
}
}
* Test IRadio.setIndicationFilter_1_2()
*/
TEST_F(RadioHidlTest_v1_2, setIndicationFilter_1_2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
- Return<void> res =
- radio_v1_2->setIndicationFilter_1_2(serial, static_cast<int>(IndicationFilter::ALL));
+ Return<void> res = radio_v1_2->setIndicationFilter_1_2(
+ serial, static_cast<int>(::android::hardware::radio::V1_2::IndicationFilter::ALL));
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setSignalStrengthReportingCriteria() with invalid hysteresisDb
*/
TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_invalidHysteresisDb) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
serial, 5000,
10, // hysteresisDb too large given threshold list deltas
- {-109, -103, -97, -89}, V1_2::AccessNetwork::GERAN);
+ {-109, -103, -97, -89}, ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
@@ -405,10 +402,10 @@ TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_invalidHysteresisD
* Test IRadio.setSignalStrengthReportingCriteria() with empty parameters
*/
TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_EmptyParams) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
- Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(serial, 0, 0, {},
- V1_2::AccessNetwork::GERAN);
+ Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
+ serial, 0, 0, {}, ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setSignalStrengthReportingCriteria() for GERAN
*/
TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Geran) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
- serial, 5000, 2, {-109, -103, -97, -89}, V1_2::AccessNetwork::GERAN);
+ serial, 5000, 2, {-109, -103, -97, -89},
+ ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setSignalStrengthReportingCriteria() for UTRAN
*/
TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Utran) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
- serial, 5000, 2, {-110, -97, -73, -49, -25}, V1_2::AccessNetwork::UTRAN);
+ serial, 5000, 2, {-110, -97, -73, -49, -25},
+ ::android::hardware::radio::V1_2::AccessNetwork::UTRAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setSignalStrengthReportingCriteria() for EUTRAN
*/
TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Eutran) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
- serial, 5000, 2, {-140, -128, -118, -108, -98, -44}, V1_2::AccessNetwork::EUTRAN);
+ serial, 5000, 2, {-140, -128, -118, -108, -98, -44},
+ ::android::hardware::radio::V1_2::AccessNetwork::EUTRAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setSignalStrengthReportingCriteria() for CDMA2000
*/
TEST_F(RadioHidlTest_v1_2, setSignalStrengthReportingCriteria_Cdma2000) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setSignalStrengthReportingCriteria(
- serial, 5000, 2, {-105, -90, -75, -65}, V1_2::AccessNetwork::CDMA2000);
+ serial, 5000, 2, {-105, -90, -75, -65},
+ ::android::hardware::radio::V1_2::AccessNetwork::CDMA2000);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setLinkCapacityReportingCriteria() invalid hysteresisDlKbps
*/
TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisDlKbps) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
serial, 5000,
5000, // hysteresisDlKbps too big for thresholds delta
- 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, V1_2::AccessNetwork::GERAN);
+ 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000},
+ ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
@@ -515,12 +517,13 @@ TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisDlK
* Test IRadio.setLinkCapacityReportingCriteria() invalid hysteresisUlKbps
*/
TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisUlKbps) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
serial, 5000, 500,
1000, // hysteresisUlKbps too big for thresholds delta
- {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, V1_2::AccessNetwork::GERAN);
+ {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000},
+ ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
@@ -535,10 +538,10 @@ TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_invalidHysteresisUlK
* Test IRadio.setLinkCapacityReportingCriteria() empty params
*/
TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_emptyParams) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
- Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(serial, 0, 0, 0, {}, {},
- V1_2::AccessNetwork::GERAN);
+ Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
+ serial, 0, 0, 0, {}, {}, ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setLinkCapacityReportingCriteria() GERAN
*/
TEST_F(RadioHidlTest_v1_2, setLinkCapacityReportingCriteria_Geran) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
Return<void> res = radio_v1_2->setLinkCapacityReportingCriteria(
serial, 5000, 500, 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000},
- V1_2::AccessNetwork::GERAN);
+ ::android::hardware::radio::V1_2::AccessNetwork::GERAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
* Test IRadio.setupDataCall_1_2() for the response returned.
*/
TEST_F(RadioHidlTest_v1_2, setupDataCall_1_2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
- V1_2::AccessNetwork accessNetwork = V1_2::AccessNetwork::EUTRAN;
+ ::android::hardware::radio::V1_2::AccessNetwork accessNetwork =
+ ::android::hardware::radio::V1_2::AccessNetwork::EUTRAN;
DataProfileInfo dataProfileInfo;
memset(&dataProfileInfo, 0, sizeof(dataProfileInfo));
bool roamingAllowed = false;
bool isRoaming = false;
- V1_2::DataRequestReason reason = V1_2::DataRequestReason::NORMAL;
+ ::android::hardware::radio::V1_2::DataRequestReason reason =
+ ::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
std::vector<hidl_string> addresses = {""};
std::vector<hidl_string> dnses = {""};
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_2->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS,
RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW, RadioError::REQUEST_NOT_SUPPORTED}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_2->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS,
* Test IRadio.deactivateDataCall_1_2() for the response returned.
*/
TEST_F(RadioHidlTest_v1_2, deactivateDataCall_1_2) {
- const int serial = GetRandomSerialNumber();
+ serial = GetRandomSerialNumber();
int cid = 1;
- V1_2::DataRequestReason reason = V1_2::DataRequestReason::NORMAL;
+ ::android::hardware::radio::V1_2::DataRequestReason reason =
+ ::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
Return<void> res = radio_v1_2->deactivateDataCall_1_2(serial, cid, reason);
ASSERT_OK(res);
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
- if (cardStatus.cardState == CardState::ABSENT) {
+ if (cardStatus.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_2->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_CALL_ID,
RadioError::INVALID_STATE, RadioError::INVALID_ARGUMENTS,
RadioError::REQUEST_NOT_SUPPORTED, RadioError::CANCELLED, RadioError::SIM_ABSENT}));
- } else if (cardStatus.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_2->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_CALL_ID,
radioRsp_v1_2->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NOT_PROVISIONED}));
}
+
+/*
+ * Test IRadio.getAvailableBandModes() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_2, getAvailableBandModes) {
+ int serial = GetRandomSerialNumber();
+
+ Return<void> res = radio_v1_2->getAvailableBandModes(serial);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
+ ALOGI("getAvailableBandModes, rspInfo.error = %s\n",
+ toString(radioRsp_v1_2->rspInfo.error).c_str());
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_2->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR,
+ RadioError::INTERNAL_ERR,
+ // If REQUEST_NOT_SUPPORTED is returned, then it should also be returned
+ // for setRandMode().
+ RadioError::REQUEST_NOT_SUPPORTED}));
+ bool hasUnspecifiedBandMode = false;
+ if (radioRsp_v1_2->rspInfo.error == RadioError::NONE) {
+ for (const RadioBandMode& mode : radioRsp_v1_2->radioBandModes) {
+ // Automatic mode selection must be supported
+ if (mode == RadioBandMode::BAND_MODE_UNSPECIFIED) hasUnspecifiedBandMode = true;
+ }
+ ASSERT_TRUE(hasUnspecifiedBandMode);
+ }
+}
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
index 4f05effdc9e87a844672bff9674cf048bb5e8453..fd1876eee6a7659466125c23bf8f931cb671e713 100644 (file)
#include <radio_hidl_hal_utils_v1_2.h>
void RadioHidlTest_v1_2::SetUp() {
- radio_v1_2 = ::testing::VtsHalHidlTargetTestBase::getService<V1_2::IRadio>(
- hidl_string(RADIO_SERVICE_NAME));
+ radio_v1_2 =
+ ::testing::VtsHalHidlTargetTestBase::getService<::android::hardware::radio::V1_2::IRadio>(
+ RadioHidlEnvironment::Instance()
+ ->getServiceName<::android::hardware::radio::V1_2::IRadio>(
+ hidl_string(RADIO_SERVICE_NAME)));
+ if (radio_v1_2 == NULL) {
+ sleep(60);
+ radio_v1_2 = ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::V1_2::IRadio>(
+ RadioHidlEnvironment::Instance()
+ ->getServiceName<::android::hardware::radio::V1_2::IRadio>(
+ hidl_string(RADIO_SERVICE_NAME)));
+ }
ASSERT_NE(nullptr, radio_v1_2.get());
radioRsp_v1_2 = new (std::nothrow) RadioResponse_v1_2(*this);
radio_v1_2->setResponseFunctions(radioRsp_v1_2, radioInd_v1_2);
- int serial = GetRandomSerialNumber();
- radio_v1_2->getIccCardStatus(serial);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
+ updateSimCardStatus();
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_2->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_2->rspInfo.serial);
EXPECT_EQ(RadioError::NONE, radioRsp_v1_2->rspInfo.error);
+
+ /* Enforce Vts Testing with Sim Status Present only. */
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.cardState);
}
/*
* Notify that the response message is received.
*/
-void RadioHidlTest_v1_2::notify() {
+void RadioHidlTest_v1_2::notify(int receivedSerial) {
std::unique_lock<std::mutex> lock(mtx_);
- count_++;
- cv_.notify_one();
+ if (serial == receivedSerial) {
+ count_++;
+ cv_.notify_one();
+ }
}
/*
count_--;
return status;
}
+
+void RadioHidlTest_v1_2::updateSimCardStatus() {
+ serial = GetRandomSerialNumber();
+ radio_v1_2->getIccCardStatus(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h b/radio/1.2/vts/functional/radio_hidl_hal_utils_v1_2.h
index ce46878a7a8e7618f32ebbbb3f0e1f2d9eb75a8c..9086408b1723c8526d045478259c928283fe990e 100644 (file)
#include <condition_variable>
#include <mutex>
-#include <android/hardware/radio/1.1/IRadioIndication.h>
-#include <android/hardware/radio/1.1/IRadioResponse.h>
#include <android/hardware/radio/1.2/IRadio.h>
+#include <android/hardware/radio/1.2/IRadioIndication.h>
+#include <android/hardware/radio/1.2/IRadioResponse.h>
#include <android/hardware/radio/1.2/types.h>
#include "vts_test_util.h"
-using namespace ::android::hardware::radio;
+using namespace ::android::hardware::radio::V1_2;
using namespace ::android::hardware::radio::V1_1;
using namespace ::android::hardware::radio::V1_0;
#define RADIO_SERVICE_NAME "slot1"
class RadioHidlTest_v1_2;
-extern CardStatus cardStatus;
+extern ::android::hardware::radio::V1_2::CardStatus cardStatus;
/* Callback class for radio response v1_2*/
-class RadioResponse_v1_2 : public V1_1::IRadioResponse {
+class RadioResponse_v1_2 : public ::android::hardware::radio::V1_2::IRadioResponse {
protected:
RadioHidlTest_v1_2& parent_v1_2;
public:
+ hidl_vec<RadioBandMode> radioBandModes;
+
RadioResponseInfo rspInfo;
RadioResponse_v1_2(RadioHidlTest_v1_2& parent_v1_2);
virtual ~RadioResponse_v1_2() = default;
- Return<void> getIccCardStatusResponse(const RadioResponseInfo& info,
- const CardStatus& cardStatus);
+ Return<void> getIccCardStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::CardStatus& cardStatus);
Return<void> supplyIccPinForAppResponse(const RadioResponseInfo& info,
int32_t remainingRetries);
Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
int32_t remainingRetries);
- Return<void> getCurrentCallsResponse(const RadioResponseInfo& info,
- const ::android::hardware::hidl_vec<Call>& calls);
+ Return<void> getCurrentCallsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
Return<void> dialResponse(const RadioResponseInfo& info);
Return<void> getLastCallFailCauseResponse(const RadioResponseInfo& info,
const LastCallFailCauseInfo& failCauseInfo);
- Return<void> getSignalStrengthResponse(const RadioResponseInfo& info,
- const SignalStrength& sigStrength);
+ Return<void> getSignalStrengthResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::SignalStrength& sigStrength);
- Return<void> getVoiceRegistrationStateResponse(const RadioResponseInfo& info,
- const VoiceRegStateResult& voiceRegResponse);
+ Return<void> getVoiceRegistrationStateResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse);
- Return<void> getDataRegistrationStateResponse(const RadioResponseInfo& info,
- const DataRegStateResult& dataRegResponse);
+ Return<void> getDataRegistrationStateResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse);
Return<void> getOperatorResponse(const RadioResponseInfo& info,
const ::android::hardware::hidl_string& longName,
Return<void> getVoiceRadioTechnologyResponse(const RadioResponseInfo& info,
RadioTechnology rat);
- Return<void> getCellInfoListResponse(const RadioResponseInfo& info,
- const ::android::hardware::hidl_vec<CellInfo>& cellInfo);
+ Return<void> getCellInfoListResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>& cellInfo);
Return<void> setCellInfoListRateResponse(const RadioResponseInfo& info);
Return<void> setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info);
- Return<void> getIccCardStatusResponse_1_2(const RadioResponseInfo& info,
- const CardStatus& card_status);
+ Return<void> getIccCardStatusResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::CardStatus& card_status);
- Return<void> getCurrentCallsResponse_1_2(const RadioResponseInfo& info,
- const ::android::hardware::hidl_vec<Call>& calls);
+ Return<void> getCurrentCallsResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls);
- Return<void> getSignalStrengthResponse_1_2(const RadioResponseInfo& info,
- const SignalStrength& sig_strength);
+ Return<void> getSignalStrengthResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::SignalStrength& sig_strength);
Return<void> getCellInfoListResponse_1_2(
- const RadioResponseInfo& info, const ::android::hardware::hidl_vec<CellInfo>& cellInfo);
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>& cellInfo);
Return<void> getVoiceRegistrationStateResponse_1_2(
- const RadioResponseInfo& info, const V1_2::VoiceRegStateResult& voiceRegResponse);
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse);
Return<void> getDataRegistrationStateResponse_1_2(
- const RadioResponseInfo& info, const V1_2::DataRegStateResult& dataRegResponse);
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse);
};
/* Callback class for radio indication */
-class RadioIndication_v1_2 : public V1_1::IRadioIndication {
+class RadioIndication_v1_2 : public ::android::hardware::radio::V1_2::IRadioIndication {
protected:
RadioHidlTest_v1_2& parent_v1_2;
virtual ~RadioIndication_v1_2() = default;
/* 1.2 Api */
- Return<void> networkScanResult_1_2(RadioIndicationType type,
- const V1_2::NetworkScanResult& result);
+ Return<void> networkScanResult_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::NetworkScanResult& result);
- Return<void> cellInfoList_1_2(RadioIndicationType type,
- const ::android::hardware::hidl_vec<V1_2::CellInfo>& records);
+ Return<void> cellInfoList_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>& records);
- Return<void> currentLinkCapacityEstimate(RadioIndicationType type,
- const V1_2::LinkCapacityEstimate& lce);
+ Return<void> currentLinkCapacityEstimate(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce);
Return<void> currentPhysicalChannelConfigs(
RadioIndicationType type,
- const ::android::hardware::hidl_vec<V1_2::PhysicalChannelConfig>& configs);
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::PhysicalChannelConfig>& configs);
- Return<void> currentSignalStrength_1_2(RadioIndicationType type,
- const V1_2::SignalStrength& signalStrength);
+ Return<void> currentSignalStrength_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::SignalStrength& signalStrength);
/* 1.1 Api */
Return<void> carrierInfoForImsiEncryption(RadioIndicationType info);
- Return<void> networkScanResult(RadioIndicationType type, const NetworkScanResult& result);
+ Return<void> networkScanResult(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_1::NetworkScanResult& result);
Return<void> keepaliveStatus(RadioIndicationType type, const KeepaliveStatus& status);
const ::android::hardware::hidl_string& nitzTime,
uint64_t receivedTime);
- Return<void> currentSignalStrength(RadioIndicationType type,
- const SignalStrength& signalStrength);
+ Return<void> currentSignalStrength(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_0::SignalStrength& signalStrength);
Return<void> dataCallListChanged(
RadioIndicationType type, const ::android::hardware::hidl_vec<SetupDataCallResult>& dcList);
Return<void> voiceRadioTechChanged(RadioIndicationType type, RadioTechnology rat);
- Return<void> cellInfoList(RadioIndicationType type,
- const ::android::hardware::hidl_vec<CellInfo>& records);
+ Return<void> cellInfoList(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>& records);
Return<void> imsNetworkStateChanged(RadioIndicationType type);
const ::android::hardware::hidl_string& reason);
};
+// Test environment for Radio HIDL HAL.
+class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static RadioHidlEnvironment* Instance() {
+ static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
+ return instance;
+ }
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::radio::V1_2::IRadio>();
+ }
+
+ private:
+ RadioHidlEnvironment() {}
+};
+
// The main test class for Radio HIDL.
class RadioHidlTest_v1_2 : public ::testing::VtsHalHidlTargetTestBase {
protected:
std::condition_variable cv_;
int count_;
+ /* Serial number for radio request */
+ int serial;
+
+ /* Update Sim Card Status */
+ void updateSimCardStatus();
+
public:
virtual void SetUp() override;
/* Used as a mechanism to inform the test about data/event callback */
- void notify();
+ void notify(int receivedSerial);
/* Test code calls this function to wait for response */
std::cv_status wait();
/* radio service handle */
- sp<V1_2::IRadio> radio_v1_2;
+ sp<::android::hardware::radio::V1_2::IRadio> radio_v1_2;
/* radio response handle */
sp<RadioResponse_v1_2> radioRsp_v1_2;
diff --git a/radio/1.2/vts/functional/radio_indication.cpp b/radio/1.2/vts/functional/radio_indication.cpp
index 57f5cb064bd91cafe8fa9b1c3d079ddee71159f1..eba9dc07459020efa01163b54c4a35d2c96b154c 100644 (file)
@@ -20,29 +20,33 @@ RadioIndication_v1_2::RadioIndication_v1_2(RadioHidlTest_v1_2& parent) : parent_
/* 1.2 Apis */
Return<void> RadioIndication_v1_2::networkScanResult_1_2(
- RadioIndicationType /*type*/, const V1_2::NetworkScanResult& /*result*/) {
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) {
return Void();
}
Return<void> RadioIndication_v1_2::cellInfoList_1_2(
RadioIndicationType /*type*/,
- const ::android::hardware::hidl_vec<V1_2::CellInfo>& /*records*/) {
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>& /*records*/) {
return Void();
}
Return<void> RadioIndication_v1_2::currentLinkCapacityEstimate(
- RadioIndicationType /*type*/, const V1_2::LinkCapacityEstimate& /*lce*/) {
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) {
return Void();
}
Return<void> RadioIndication_v1_2::currentPhysicalChannelConfigs(
RadioIndicationType /*type*/,
- const ::android::hardware::hidl_vec<V1_2::PhysicalChannelConfig>& /*configs*/) {
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) {
return Void();
}
Return<void> RadioIndication_v1_2::currentSignalStrength_1_2(
- RadioIndicationType /*type*/, const V1_2::SignalStrength& /*signalStrength*/) {
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) {
return Void();
}
return Void();
}
-Return<void> RadioIndication_v1_2::networkScanResult(RadioIndicationType /*type*/,
- const NetworkScanResult& /*result*/) {
+Return<void> RadioIndication_v1_2::networkScanResult(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) {
return Void();
}
return Void();
}
-Return<void> RadioIndication_v1_2::currentSignalStrength(RadioIndicationType /*type*/,
- const SignalStrength& /*signalStrength*/) {
+Return<void> RadioIndication_v1_2::currentSignalStrength(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) {
return Void();
}
@@ -224,7 +230,8 @@ Return<void> RadioIndication_v1_2::voiceRadioTechChanged(RadioIndicationType /*t
}
Return<void> RadioIndication_v1_2::cellInfoList(
- RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<CellInfo>& /*records*/) {
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>& /*records*/) {
return Void();
}
Return<void> RadioIndication_v1_2::modemReset(RadioIndicationType /*type*/,
const ::android::hardware::hidl_string& /*reason*/) {
return Void();
-}
+}
\ No newline at end of file
diff --git a/radio/1.2/vts/functional/radio_response.cpp b/radio/1.2/vts/functional/radio_response.cpp
index 9195689ca8fa8f11fce83abd4c302091a1f53a76..f6bead21e7db8cdac2188678239b2f0efb1e91e2 100644 (file)
#include <radio_hidl_hal_utils_v1_2.h>
-CardStatus cardStatus;
+::android::hardware::radio::V1_2::CardStatus cardStatus;
RadioResponse_v1_2::RadioResponse_v1_2(RadioHidlTest_v1_2& parent) : parent_v1_2(parent) {}
/* 1.0 Apis */
-Return<void> RadioResponse_v1_2::getIccCardStatusResponse(const RadioResponseInfo& /*info*/,
- const CardStatus& /*card_status*/) {
+Return<void> RadioResponse_v1_2::getIccCardStatusResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) {
return Void();
}
}
Return<void> RadioResponse_v1_2::getCurrentCallsResponse(
- const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<Call>& /*calls*/) {
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
return Void();
}
return Void();
}
-Return<void> RadioResponse_v1_2::getSignalStrengthResponse(const RadioResponseInfo& /*info*/,
- const SignalStrength& /*sig_strength*/) {
+Return<void> RadioResponse_v1_2::getSignalStrengthResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) {
return Void();
}
Return<void> RadioResponse_v1_2::getVoiceRegistrationStateResponse(
- const RadioResponseInfo& /*info*/, const VoiceRegStateResult& /*voiceRegResponse*/) {
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) {
return Void();
}
Return<void> RadioResponse_v1_2::getDataRegistrationStateResponse(
- const RadioResponseInfo& /*info*/, const DataRegStateResult& /*dataRegResponse*/) {
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) {
return Void();
}
@@ -150,7 +155,7 @@ Return<void> RadioResponse_v1_2::sendSMSExpectMoreResponse(const RadioResponseIn
Return<void> RadioResponse_v1_2::setupDataCallResponse(const RadioResponseInfo& info,
const SetupDataCallResult& /*dcResponse*/) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
@@ -206,7 +211,7 @@ Return<void> RadioResponse_v1_2::acceptCallResponse(const RadioResponseInfo& /*i
Return<void> RadioResponse_v1_2::deactivateDataCallResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
@@ -312,8 +317,10 @@ Return<void> RadioResponse_v1_2::setBandModeResponse(const RadioResponseInfo& /*
}
Return<void> RadioResponse_v1_2::getAvailableBandModesResponse(
- const RadioResponseInfo& /*info*/,
- const ::android::hardware::hidl_vec<RadioBandMode>& /*bandModes*/) {
+ const RadioResponseInfo& info, const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) {
+ rspInfo = info;
+ radioBandModes = bandModes;
+ parent_v1_2.notify(info.serial);
return Void();
}
@@ -515,7 +522,7 @@ Return<void> RadioResponse_v1_2::getVoiceRadioTechnologyResponse(const RadioResp
Return<void> RadioResponse_v1_2::getCellInfoListResponse(
const RadioResponseInfo& /*info*/,
- const ::android::hardware::hidl_vec<CellInfo>& /*cellInfo*/) {
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) {
return Void();
}
@@ -670,13 +677,13 @@ Return<void> RadioResponse_v1_2::setSimCardPowerResponse_1_1(const RadioResponse
Return<void> RadioResponse_v1_2::startNetworkScanResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_2::stopNetworkScanResponse(const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
@@ -693,52 +700,58 @@ Return<void> RadioResponse_v1_2::stopKeepaliveResponse(const RadioResponseInfo&
Return<void> RadioResponse_v1_2::setSignalStrengthReportingCriteriaResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_2::setLinkCapacityReportingCriteriaResponse(
const RadioResponseInfo& info) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
-Return<void> RadioResponse_v1_2::getIccCardStatusResponse_1_2(const RadioResponseInfo& info,
- const CardStatus& card_status) {
+Return<void> RadioResponse_v1_2::getIccCardStatusResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::CardStatus& card_status) {
rspInfo = info;
cardStatus = card_status;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_2::getCurrentCallsResponse_1_2(
- const RadioResponseInfo& info, const ::android::hardware::hidl_vec<Call>& /*calls*/) {
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& /*calls*/) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_2::getSignalStrengthResponse_1_2(
- const RadioResponseInfo& info, const SignalStrength& /*sig_strength*/) {
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_2::getCellInfoListResponse_1_2(
- const RadioResponseInfo& info, const ::android::hardware::hidl_vec<CellInfo>& /*cellInfo*/) {
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) {
rspInfo = info;
- parent_v1_2.notify();
+ parent_v1_2.notify(info.serial);
return Void();
}
Return<void> RadioResponse_v1_2::getVoiceRegistrationStateResponse_1_2(
- const RadioResponseInfo& /*info*/, const V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
return Void();
}
Return<void> RadioResponse_v1_2::getDataRegistrationStateResponse_1_2(
- const RadioResponseInfo& /*info*/, const V1_2::DataRegStateResult& /*dataRegResponse*/) {
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) {
return Void();
-}
+}
\ No newline at end of file
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
index dab81e2a2316e955d33c2646791aafb2ab515411..3ea3e8dcac114dce56feee1037dee94ae19e8d81 100644 (file)
EXPECT_LE((unsigned int)2, response.selectResponse.size());
EXPECT_LE(1, response.channelNumber);
std::vector<uint8_t> command = DATA_APDU;
+ command[0] |= response.channelNumber;
std::vector<uint8_t> transmitResponse;
se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
transmitResponse.resize(res.size());
}
});
if (statusReturned == SecureElementStatus::SUCCESS) {
- EXPECT_LE((unsigned int)3, response.size());
+ EXPECT_LE((unsigned int)2, response.size());
+ se_->closeChannel(0);
return;
}
EXPECT_EQ(SecureElementStatus::UNSUPPORTED_OPERATION, statusReturned);
diff --git a/tv/cec/1.0/types.hal b/tv/cec/1.0/types.hal
index a1853a31cca3a45a41d3bb076a225d8c99054492..c734c4d7ad2a34bb4917f9483a41de182616712d 100644 (file)
--- a/tv/cec/1.0/types.hal
+++ b/tv/cec/1.0/types.hal
*/
SYSTEM_CEC_CONTROL = 3,
- /** Option 4 not used */
+ /* Option 4 not used */
};
struct CecMessage {
diff --git a/usb/1.1/IUsb.hal b/usb/1.1/IUsb.hal
index 9cedea0c69630d02e10b2361e082de1d54f50c10..606928bf9840806ab3365c91580a83bf2a90be2e 100644 (file)
--- a/usb/1.1/IUsb.hal
+++ b/usb/1.1/IUsb.hal
import android.hardware.usb@1.0;
-interface IUsb extends android.hardware.usb@1.0::IUsb {
- /**
- * The setCallback function in V1_0 is used to register the V1_1
- * IUsbCallback object as well. The implementation can use the
- * castFrom method to cast the IUsbCallback object.
- */
-};
-
+/*
+ * The setCallback function in V1_0 is used to register the V1_1
+ * IUsbCallback object as well. The implementation can use the
+ * castFrom method to cast the IUsbCallback object.
+ */
+interface IUsb extends android.hardware.usb@1.0::IUsb {};
index 243748ffc02ae4d0496eaced98c5a600ce67b329..b908591128837cca3a51410f331008b39aef8afe 100644 (file)
/**
* Interface used to represent a single NAN iface.
*/
-interface IWifiP2pIface extends IWifiIface {
- /** TODO(rpius): Add methods to the interface. */
-};
+interface IWifiP2pIface extends IWifiIface {};