Merge "Add StaLinkLayerStats V1_3"
diff --git a/health/filesystem/1.0/Android.bp b/atrace/1.0/Android.bp
similarity index 71%
copy from health/filesystem/1.0/Android.bp
copy to atrace/1.0/Android.bp
index 74b9bc3..f7c9078 100644
--- a/health/filesystem/1.0/Android.bp
+++ b/atrace/1.0/Android.bp
@@ -1,20 +1,21 @@
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
- name: "android.hardware.health.filesystem@1.0",
+ name: "android.hardware.atrace@1.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"types.hal",
- "IFileSystem.hal",
+ "IAtraceDevice.hal",
],
interfaces: [
"android.hidl.base@1.0",
],
types: [
- "Result",
+ "Status",
+ "TracingCategory",
],
gen_java: true,
}
diff --git a/atrace/1.0/IAtraceDevice.hal b/atrace/1.0/IAtraceDevice.hal
new file mode 100644
index 0000000..b6e78b4
--- /dev/null
+++ b/atrace/1.0/IAtraceDevice.hal
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package android.hardware.atrace@1.0;
+
+interface IAtraceDevice {
+ /**
+ * Get vendor extended atrace points.
+ *
+ *
+ * @return categories of tracing points the device extended.
+ */
+ listCategories() generates (vec<TracingCategory> categories);
+
+ /**
+ * A hook when atrace set to enable specific categories, so HAL
+ * can enable kernel tracing points and/or notify other things
+ * for userspace tracing turning on.
+ *
+ * @param categories A vector of strings of categories (corresponding to
+ * TracingCategory.name) atrace needs to be enabled.
+ *
+ * @return status SUCCESS on success,
+ * ERROR_TRACING_POINT on error with enabling categories,
+ * ERROR_INVALID_ARGUMENT on invalid argument passed.
+ */
+ enableCategories(vec<string> categories) generates (Status status);
+
+ /**
+ * A hook when atrace set to clean up tracing categories, so HAL
+ * can disable all kernel tracing points and/or notify other things
+ * for userspace tracing turning off.
+ *
+ * @return status SUCCESS on success,
+ * ERROR_TRACING_POINT on error with disabling categories.
+ */
+ disableAllCategories() generates (Status status);
+};
diff --git a/atrace/1.0/default/Android.bp b/atrace/1.0/default/Android.bp
new file mode 100644
index 0000000..bcaf064
--- /dev/null
+++ b/atrace/1.0/default/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+
+cc_binary {
+ name: "android.hardware.atrace@1.0-service",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.atrace@1.0-service.rc"],
+ vintf_fragments: ["android.hardware.atrace@1.0-service.xml"],
+ srcs: [
+ "AtraceDevice.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.atrace@1.0",
+ ],
+}
diff --git a/atrace/1.0/default/AtraceDevice.cpp b/atrace/1.0/default/AtraceDevice.cpp
new file mode 100644
index 0000000..43bcd9a
--- /dev/null
+++ b/atrace/1.0/default/AtraceDevice.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+
+#include "AtraceDevice.h"
+
+namespace android {
+namespace hardware {
+namespace atrace {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::atrace::V1_0::Status;
+using ::android::hardware::atrace::V1_0::TracingCategory;
+
+struct TracingConfig {
+ std::string description;
+ std::vector<std::pair<std::string, bool>> paths;
+};
+
+// This is a map stores categories and their sysfs paths with required flags
+const std::map<std::string, TracingConfig> kTracingMap = {
+ // gfx
+ {
+ "gfx",
+ {"Graphics",
+ {{"/sys/kernel/debug/tracing/events/mdss/enable", false},
+ {"/sys/kernel/debug/tracing/events/sde/enable", false},
+ {"/sys/kernel/debug/tracing/events/mali_systrace/enable", false}}},
+ },
+ {
+ "ion",
+ {"ION allocation",
+ {{"/sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable", true}}},
+ },
+};
+
+// Methods from ::android::hardware::atrace::V1_0::IAtraceDevice follow.
+Return<void> AtraceDevice::listCategories(listCategories_cb _hidl_cb) {
+ hidl_vec<TracingCategory> categories;
+ categories.resize(kTracingMap.size());
+ std::size_t i = 0;
+ for (auto& c : kTracingMap) {
+ categories[i].name = c.first;
+ categories[i].description = c.second.description;
+ i++;
+ }
+ _hidl_cb(categories);
+ return Void();
+}
+
+Return<::android::hardware::atrace::V1_0::Status> AtraceDevice::enableCategories(
+ const hidl_vec<hidl_string>& categories) {
+ if (!categories.size()) {
+ return Status::ERROR_INVALID_ARGUMENT;
+ }
+ for (auto& c : categories) {
+ if (kTracingMap.count(c)) {
+ for (auto& p : kTracingMap.at(c).paths) {
+ if (!android::base::WriteStringToFile("1", p.first)) {
+ LOG(ERROR) << "Failed to enable tracing on: " << p.first;
+ if (p.second) {
+ // disable before return
+ disableAllCategories();
+ return Status::ERROR_TRACING_POINT;
+ }
+ }
+ }
+ } else {
+ return Status::ERROR_INVALID_ARGUMENT;
+ }
+ }
+ return Status::SUCCESS;
+}
+
+Return<::android::hardware::atrace::V1_0::Status> AtraceDevice::disableAllCategories() {
+ auto ret = Status::SUCCESS;
+ for (auto& c : kTracingMap) {
+ for (auto& p : c.second.paths) {
+ if (!android::base::WriteStringToFile("0", p.first)) {
+ LOG(ERROR) << "Failed to enable tracing on: " << p.first;
+ if (p.second) {
+ ret = Status::ERROR_TRACING_POINT;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace atrace
+} // namespace hardware
+} // namespace android
diff --git a/atrace/1.0/default/AtraceDevice.h b/atrace/1.0/default/AtraceDevice.h
new file mode 100644
index 0000000..e700f89
--- /dev/null
+++ b/atrace/1.0/default/AtraceDevice.h
@@ -0,0 +1,54 @@
+/*
+ * 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 ANDROID_HARDWARE_ATRACE_V1_0_ATRACEDEVICE_H
+#define ANDROID_HARDWARE_ATRACE_V1_0_ATRACEDEVICE_H
+
+#include <android/hardware/atrace/1.0/IAtraceDevice.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace atrace {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+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;
+
+struct AtraceDevice : public IAtraceDevice {
+ // Methods from ::android::hardware::atrace::V1_0::IAtraceDevice follow.
+ Return<void> listCategories(listCategories_cb _hidl_cb) override;
+ Return<::android::hardware::atrace::V1_0::Status> enableCategories(
+ const hidl_vec<hidl_string>& categories) override;
+ Return<::android::hardware::atrace::V1_0::Status> disableAllCategories() override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace atrace
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_ATRACE_V1_0_ATRACEDEVICE_H
diff --git a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
new file mode 100644
index 0000000..eb54c39
--- /dev/null
+++ b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
@@ -0,0 +1,13 @@
+on late-init
+ # vendor graphics trace points
+ chmod 0666 /sys/kernel/debug/tracing/events/sde/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/mdss/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/mali_systrace/enable
+ # ion allocation trace point
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable
+
+service vendor.atrace-hal-1-0 /vendor/bin/hw/android.hardware.atrace@1.0-service
+ interface android.hardware.atrace@1.0::IAtraceDevice default
+ class early_hal
+ user system
+ group system
diff --git a/atrace/1.0/default/android.hardware.atrace@1.0-service.xml b/atrace/1.0/default/android.hardware.atrace@1.0-service.xml
new file mode 100644
index 0000000..fd3631c
--- /dev/null
+++ b/atrace/1.0/default/android.hardware.atrace@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.atrace</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IAtraceDevice</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/atrace/1.0/default/service.cpp b/atrace/1.0/default/service.cpp
new file mode 100644
index 0000000..662fd73
--- /dev/null
+++ b/atrace/1.0/default/service.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "android.hardware.atrace@1.0-service"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "AtraceDevice.h"
+
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::atrace::V1_0::IAtraceDevice;
+using ::android::hardware::atrace::V1_0::Status;
+using ::android::hardware::atrace::V1_0::TracingCategory;
+using ::android::hardware::atrace::V1_0::implementation::AtraceDevice;
+
+int main(int /* argc */, char* /* argv */ []) {
+ sp<IAtraceDevice> atrace = new AtraceDevice;
+ configureRpcThreadpool(1, true /* will join */);
+ if (atrace->registerAsService() != OK) {
+ ALOGE("Could not register service.");
+ return 1;
+ }
+ joinRpcThreadpool();
+
+ ALOGE("Service exited!");
+ return 1;
+}
diff --git a/health/filesystem/1.0/types.hal b/atrace/1.0/types.hal
similarity index 60%
copy from health/filesystem/1.0/types.hal
copy to atrace/1.0/types.hal
index 00431f7..f137ef6 100644
--- a/health/filesystem/1.0/types.hal
+++ b/atrace/1.0/types.hal
@@ -14,26 +14,30 @@
* limitations under the License.
*/
-package android.hardware.health.filesystem@1.0;
+package android.hardware.atrace@1.0;
-/**
- * Status values for HAL methods.
- */
-enum Result : uint32_t {
+enum Status : uint32_t {
/**
- * Execution of the method is successful.
+ * Operation completed without errors.
*/
SUCCESS = 0,
/**
- * Execution of the method timed out.
+ * Operation failed with errors on enabling tracing point.
*/
- TIMEOUT,
+ ERROR_TRACING_POINT = 1,
/**
- * An IO error is encountered when the HAL communicates with the device.
+ * Operation failed because of invalid argument.
*/
- IO_ERROR,
+ ERROR_INVALID_ARGUMENT = 2
+};
+
+struct TracingCategory {
/**
- * An unknown error is encountered.
+ * Tracing category name, unique to frameworks's category.
*/
- UNKNOWN_ERROR,
+ string name;
+ /**
+ * Tracing category description.
+ */
+ string description;
};
diff --git a/atrace/1.0/vts/functional/Android.bp b/atrace/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..6b50fb5
--- /dev/null
+++ b/atrace/1.0/vts/functional/Android.bp
@@ -0,0 +1,22 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalAtraceV1_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalAtraceV1_0TargetTest.cpp"],
+ static_libs: ["android.hardware.atrace@1.0"],
+}
diff --git a/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp b/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
new file mode 100644
index 0000000..c62c2f0
--- /dev/null
+++ b/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#include <unordered_set>
+
+#include <android/hardware/atrace/1.0/IAtraceDevice.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::atrace::V1_0::IAtraceDevice;
+using ::android::hardware::atrace::V1_0::Status;
+
+// Test environment for Boot HIDL HAL.
+class AtraceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static AtraceHidlEnvironment* Instance() {
+ static AtraceHidlEnvironment* instance = new AtraceHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IAtraceDevice>(); }
+
+ private:
+ AtraceHidlEnvironment() {}
+};
+
+/**
+ * There is no expected behaviour that can be tested so these tests check the
+ * HAL doesn't crash with different execution orders.
+ */
+struct AtraceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ virtual void SetUp() override {
+ atrace = ::testing::VtsHalHidlTargetTestBase::getService<IAtraceDevice>(
+ AtraceHidlEnvironment::Instance()->getServiceName<IAtraceDevice>());
+ ASSERT_NE(atrace, nullptr);
+ }
+
+ sp<IAtraceDevice> atrace;
+};
+
+hidl_vec<hidl_string> getVendorCategoryName(sp<IAtraceDevice> atrace) {
+ std::unordered_set<std::string> categories_set;
+ Return<void> ret = atrace->listCategories([&](const auto& list) {
+ for (const auto& category : list) {
+ std::string name = category.name;
+ if (categories_set.count(name)) {
+ ADD_FAILURE() << "Duplicate category: " << name;
+ } else {
+ categories_set.emplace(name);
+ }
+ }
+ });
+ if (!ret.isOk()) {
+ ADD_FAILURE();
+ }
+ hidl_vec<hidl_string> categories;
+ categories.resize(categories_set.size());
+ std::size_t i = 0;
+ for (auto& c : categories_set) {
+ categories[i++] = c;
+ }
+ return categories;
+}
+
+/* list categories from vendors. */
+TEST_F(AtraceHidlTest, listCategories) {
+ hidl_vec<hidl_string> vnd_categories = getVendorCategoryName(atrace);
+ EXPECT_NE(0, vnd_categories.size());
+}
+
+/* enable categories. */
+TEST_F(AtraceHidlTest, enableCategories) {
+ hidl_vec<hidl_string> vnd_categories = getVendorCategoryName(atrace);
+ // empty Category with ERROR_INVALID_ARGUMENT
+ hidl_vec<hidl_string> empty_categories;
+ auto ret = atrace->enableCategories(empty_categories);
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(Status::ERROR_INVALID_ARGUMENT, ret);
+ // non-empty categories SUCCESS
+ ret = atrace->enableCategories(vnd_categories);
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(Status::SUCCESS, ret);
+}
+
+/* enable categories. */
+TEST_F(AtraceHidlTest, disableAllCategories) {
+ auto ret = atrace->disableAllCategories();
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(Status::SUCCESS, ret);
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(AtraceHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ AtraceHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
index 43d7fe1..e6ae03e 100644
--- a/audio/common/all-versions/default/service/Android.mk
+++ b/audio/common/all-versions/default/service/Android.mk
@@ -31,12 +31,14 @@
LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := \
+ libcutils \
libbinder \
libhidlbase \
libhidltransport \
liblog \
libutils \
libhardware \
+ libhwbinder \
android.hardware.audio@2.0 \
android.hardware.audio@4.0 \
android.hardware.audio.common@2.0 \
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index c7ce638..ff1394e 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -24,16 +24,26 @@
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
#include <binder/ProcessState.h>
+#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/LegacySupport.h>
+#include <hwbinder/ProcessState.h>
using namespace android::hardware;
using android::OK;
int main(int /* argc */, char* /* argv */ []) {
- android::ProcessState::initWithDriver("/dev/vndbinder");
+ ::android::ProcessState::initWithDriver("/dev/vndbinder");
// start a threadpool for vndbinder interactions
- android::ProcessState::self()->startThreadPool();
+ ::android::ProcessState::self()->startThreadPool();
+
+ const int32_t defaultValue = -1;
+ int32_t value =
+ property_get_int32("persist.vendor.audio.service.hwbinder.size_kbyte", defaultValue);
+ if (value != defaultValue) {
+ ALOGD("Configuring hwbinder with mmap size %d KBytes", value);
+ ProcessState::initWithMmapSize(static_cast<size_t>(value) * 1024);
+ }
configureRpcThreadpool(16, true /*callerWillJoin*/);
bool fail = registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index f4ab542..3a7c284 100644
--- a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -29,6 +29,8 @@
#include <fcntl.h>
#include <unistd.h>
+#include <hwbinder/IPCThreadState.h>
+
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
@@ -63,6 +65,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using ::android::hardware::IPCThreadState;
using ::android::hardware::kSynchronizedReadWrite;
using ::android::hardware::MessageQueue;
using ::android::hardware::MQDescriptorSync;
@@ -170,15 +173,25 @@
TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
doc::test("Calling openDevice(\"primary\") should return the primary device.");
- Result result;
- sp<IDevice> baseDevice;
- ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
- ASSERT_OK(result);
- ASSERT_TRUE(baseDevice != nullptr);
+ {
+ Result result;
+ sp<IDevice> baseDevice;
+ ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
+ ASSERT_OK(result);
+ ASSERT_TRUE(baseDevice != nullptr);
- Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
- ASSERT_TRUE(primaryDevice.isOk());
- ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+ Return<sp<IPrimaryDevice>> primaryDevice = IPrimaryDevice::castFrom(baseDevice);
+ ASSERT_TRUE(primaryDevice.isOk());
+ ASSERT_TRUE(sp<IPrimaryDevice>(primaryDevice) != nullptr);
+ } // Destroy local IDevice proxy
+ // FIXME: there is no way to know when the remote IDevice is being destroyed
+ // Binder does not support testing if an object is alive, thus
+ // wait for 100ms to let the binder destruction propagates and
+ // the remote device has the time to be destroyed.
+ // flushCommand makes sure all local command are sent, thus should reduce
+ // the latency between local and remote destruction.
+ IPCThreadState::self()->flushCommands();
+ usleep(100);
}
//////////////////////////////////////////////////////////////////////////////
@@ -1470,6 +1483,7 @@
"Make sure setBtHfpVolume is either not supported or "
"only succeed if volume is in [0,1]");
auto ret = device->setBtHfpVolume(0.0);
+ ASSERT_TRUE(ret.isOk());
if (ret == Result::NOT_SUPPORTED) {
doc::partialTest("setBtHfpVolume is not supported");
return;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 74bbfb4..e0b54d0 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -227,6 +227,16 @@
{.config =
{
+ .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ // this was a zoned property on an old vhal, but it is meant to be global
+ .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ },
+ .initialValue = {.int32Values = {SEAT_1_LEFT}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::PERF_ODOMETER),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 7fe8377..4d07386 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -322,6 +322,21 @@
| VehicleArea:GLOBAL),
/**
+ * Steering angle of the vehicle
+ *
+ * Angle is in degrees. Left is negative.
+ *
+ * @change_mode VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:DEGREES
+ */
+ PERF_STEERING_ANGLE = (
+ 0x0209
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /**
* Temperature of engine coolant
*
* @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -2421,13 +2436,15 @@
NANO_SECS = 0x50,
SECS = 0x53,
YEAR = 0x59,
- KILOPASCAL = 0x70,
// Electrical Units
WATT_HOUR = 0x60,
MILLIAMPERE = 0x61,
MILLIVOLT = 0x62,
MILLIWATTS = 0x63,
+
+ KILOPASCAL = 0x70,
+ DEGREES = 0x80,
};
/**
diff --git a/biometrics/face/1.0/IBiometricsFace.hal b/biometrics/face/1.0/IBiometricsFace.hal
index f39eaeb..1c7bfb9 100644
--- a/biometrics/face/1.0/IBiometricsFace.hal
+++ b/biometrics/face/1.0/IBiometricsFace.hal
@@ -78,11 +78,15 @@
* template if the operation was preceded by some kind of strong credential
* confirmation (e.g. device password).
*
+ * @param challengeTimeoutSec A timeout in seconds, after which the driver
+ * must invalidate the challenge. This is to prevent bugs or crashes in
+ * the system from leaving a challenge enabled indefinitely.
* @return result, with its "value" parameter representing a "challenge": a
* unique and cryptographically secure random token.
*/
@callflow(next={"enroll", "revokeChallenge", "setRequireAttention"})
- generateChallenge() generates (OptionalUint64 result);
+ generateChallenge(uint32_t challengeTimeoutSec)
+ generates (OptionalUint64 result);
/**
* Enrolls a user's face.
diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal
index 92cb70d..2628af9 100644
--- a/biometrics/face/1.0/types.hal
+++ b/biometrics/face/1.0/types.hal
@@ -212,8 +212,10 @@
FACE_TOO_LEFT = 9,
/**
- * The user's face was directed away from the sensor. The user should be
- * informed to face the sensor when this is returned.
+ * The user's eyes have strayed away from the sensor. If this message is
+ * sent, the user should be informed to look at the device. If the user
+ * can't be found in the frame, one of the other acquisition messages
+ * must be sent, e.g. NOT_DETECTED.
*/
POOR_GAZE = 10,
@@ -234,7 +236,11 @@
TOO_MUCH_MOTION = 12,
/**
- * The sensor needs to be recalibrated.
+ * The sensor needs to be re-calibrated. This is an unexpected condition,
+ * and must only be sent if a serious, uncorrectable, and unrecoverable
+ * calibration issue is detected which requires user intervention, e.g.
+ * re-enrolling. The expected response to this message is to direct the
+ * user to re-enroll.
*/
RECALIBRATE = 13,
diff --git a/boot/1.0/default/Android.bp b/boot/1.0/default/Android.bp
index 67dee08..397c56d 100644
--- a/boot/1.0/default/Android.bp
+++ b/boot/1.0/default/Android.bp
@@ -2,7 +2,7 @@
name: "android.hardware.boot@1.0-impl",
defaults: ["hidl_defaults"],
relative_install_path: "hw",
- vendor_available: true,
+ vendor: true,
recovery_available: true,
srcs: ["BootControl.cpp"],
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index dc4e0f0..eb840a7 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -319,6 +319,41 @@
return OK;
}
+int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mCameraInfoLock);
+ if (physicalCameraId < 0) {
+ ALOGE("%s: Invalid physical camera ID %d", __FUNCTION__, physicalCameraId);
+ return -EINVAL;
+ }
+
+ // Only query physical camera info for 2.5 version for newer
+ int apiVersion = mModule->common.module_api_version;
+ if (apiVersion < CAMERA_MODULE_API_VERSION_2_5) {
+ ALOGE("%s: Module version must be at least 2.5 to handle getPhysicalCameraInfo",
+ __FUNCTION__);
+ return -ENODEV;
+ }
+
+ ssize_t index = mPhysicalCameraInfoMap.indexOfKey(physicalCameraId);
+ if (index == NAME_NOT_FOUND) {
+ // Get physical camera characteristics, and cache it
+ camera_metadata_t *info = nullptr;
+ ATRACE_BEGIN("camera_module->get_physical_camera_info");
+ int ret = mModule->get_physical_camera_info(physicalCameraId, &info);
+ ATRACE_END();
+ if (ret != 0) {
+ return ret;
+ }
+
+ index = mPhysicalCameraInfoMap.add(physicalCameraId, info);
+ }
+
+ assert(index != NAME_NOT_FOUND);
+ *physicalInfo = mPhysicalCameraInfoMap[index];
+ return OK;
+}
+
int CameraModule::getDeviceVersion(int cameraId) {
ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
if (index == NAME_NOT_FOUND) {
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
index deebd09..ed853bf 100644
--- a/camera/common/1.0/default/include/CameraModule.h
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -65,6 +65,7 @@
void *getDso();
// Only used by CameraProvider
void removeCamera(int cameraId);
+ int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo);
private:
// Derive camera characteristics keys defined after HAL device version
@@ -76,6 +77,7 @@
camera_module_t *mModule;
KeyedVector<int, camera_info> mCameraInfoMap;
KeyedVector<int, int> mDeviceVersionMap;
+ KeyedVector<int, camera_metadata_t*> mPhysicalCameraInfoMap;
Mutex mCameraInfoLock;
};
diff --git a/camera/device/3.2/ICameraDevice.hal b/camera/device/3.2/ICameraDevice.hal
index 1f523e4..5236bb1 100644
--- a/camera/device/3.2/ICameraDevice.hal
+++ b/camera/device/3.2/ICameraDevice.hal
@@ -148,7 +148,9 @@
* session handle for active operations.
*
* @param callback Interface to invoke by the HAL for device asynchronous
- * events.
+ * events. For HALs newer than version 3.2, HAL must use castFrom
+ * method to check the exact version of callback sent by camera service.
+ *
* @return status Status code for the operation, one of:
* OK:
* On a successful open of the camera device.
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal
index 477a3cc..225e52b 100644
--- a/camera/device/3.2/ICameraDeviceSession.hal
+++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -149,9 +149,8 @@
* - Including too many output streams of a certain format.
* - Unsupported rotation configuration
* - Stream sizes/formats don't satisfy the
- * camera3_stream_configuration_t->operation_mode requirements
- * for non-NORMAL mode, or the requested operation_mode is not
- * supported by the HAL.
+ * StreamConfigurationMode requirements for non-NORMAL mode, or
+ * the requested operation_mode is not supported by the HAL.
* - Unsupported usage flag
* The camera service cannot filter out all possible illegal stream
* configurations, since some devices may support more simultaneous
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
index dfbb976..2e80ce8 100644
--- a/camera/device/3.2/default/CameraDevice.cpp
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -101,7 +101,7 @@
}
// Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow.
-Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
+Return<void> CameraDevice::getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb) {
Status status = initStatus();
CameraResourceCost resCost;
if (status == Status::OK) {
@@ -141,7 +141,8 @@
return Void();
}
-Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) {
+Return<void> CameraDevice::getCameraCharacteristics(
+ ICameraDevice::getCameraCharacteristics_cb _hidl_cb) {
Status status = initStatus();
CameraMetadata cameraCharacteristics;
if (status == Status::OK) {
@@ -172,7 +173,8 @@
return status;
}
-Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
+Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback,
+ ICameraDevice::open_cb _hidl_cb) {
Status status = initStatus();
sp<CameraDeviceSession> session = nullptr;
diff --git a/camera/device/3.2/default/CameraDevice_3_2.h b/camera/device/3.2/default/CameraDevice_3_2.h
index 9534707..f474533 100644
--- a/camera/device/3.2/default/CameraDevice_3_2.h
+++ b/camera/device/3.2/default/CameraDevice_3_2.h
@@ -51,7 +51,7 @@
/*
* The camera device HAL implementation is opened lazily (via the open call)
*/
-struct CameraDevice : public ICameraDevice {
+struct CameraDevice : public virtual RefBase {
// Called by provider HAL. Provider HAL must ensure the uniqueness of
// CameraDevice object per cameraId, or there could be multiple CameraDevice
// trying to access the same physical camera.
@@ -60,7 +60,14 @@
CameraDevice(sp<CameraModule> module,
const std::string& cameraId,
const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
- ~CameraDevice();
+ virtual ~CameraDevice();
+
+ // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+ // dealing with minor version revs and simultaneous implementation and interface inheritance
+ virtual sp<ICameraDevice> getInterface() {
+ return new TrampolineDeviceInterface_3_2(this);
+ }
+
// Caller must use this method to check if CameraDevice ctor failed
bool isInitFailed() { return mInitFail; }
// Used by provider HAL to signal external camera disconnected
@@ -68,16 +75,16 @@
/* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
// The following method can be called without opening the actual camera device
- Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
- Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
- Return<Status> setTorchMode(TorchMode mode) override;
+ Return<void> getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb);
+ Return<void> getCameraCharacteristics(ICameraDevice::getCameraCharacteristics_cb _hidl_cb);
+ Return<Status> setTorchMode(TorchMode mode);
// Open the device HAL and also return a default capture session
- Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override;
+ Return<void> open(const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb);
// Forward the dump call to the opened session, or do nothing
- Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override;
+ Return<void> dumpState(const ::android::hardware::hidl_handle& fd);
/* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
protected:
@@ -106,6 +113,39 @@
static Status getHidlStatus(int);
Status initStatus() const;
+
+private:
+ struct TrampolineDeviceInterface_3_2 : public ICameraDevice {
+ TrampolineDeviceInterface_3_2(sp<CameraDevice> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+ override {
+ return mParent->getResourceCost(_hidl_cb);
+ }
+
+ virtual Return<void> getCameraCharacteristics(
+ V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+ return mParent->getCameraCharacteristics(_hidl_cb);
+ }
+
+ virtual Return<Status> setTorchMode(TorchMode mode) override {
+ return mParent->setTorchMode(mode);
+ }
+
+ virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+ V3_2::ICameraDevice::open_cb _hidl_cb) override {
+ return mParent->open(callback, _hidl_cb);
+ }
+
+ virtual Return<void> dumpState(const hidl_handle& fd) override {
+ return mParent->dumpState(fd);
+ }
+
+ private:
+ sp<CameraDevice> mParent;
+ };
+
};
} // namespace implementation
diff --git a/camera/device/3.4/ICameraDeviceSession.hal b/camera/device/3.4/ICameraDeviceSession.hal
index c41d90e..e1663e6 100644
--- a/camera/device/3.4/ICameraDeviceSession.hal
+++ b/camera/device/3.4/ICameraDeviceSession.hal
@@ -54,7 +54,7 @@
* - Including too many output streams of a certain format.
* - Unsupported rotation configuration
* - Stream sizes/formats don't satisfy the
- * camera3_stream_configuration_t->operation_mode requirements
+ * StreamConfigurationMode requirements
* for non-NORMAL mode, or the requested operation_mode is not
* supported by the HAL.
* - Unsupported usage flag
diff --git a/camera/device/3.5/Android.bp b/camera/device/3.5/Android.bp
new file mode 100644
index 0000000..2a9ba05
--- /dev/null
+++ b/camera/device/3.5/Android.bp
@@ -0,0 +1,33 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.device@3.5",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ICameraDevice.hal",
+ "ICameraDeviceCallback.hal",
+ "ICameraDeviceSession.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "BufferRequest",
+ "BufferRequestStatus",
+ "StreamBufferRequestError",
+ "StreamBufferRet",
+ "StreamBuffersVal",
+ "StreamConfiguration",
+ ],
+ gen_java: false,
+}
+
diff --git a/camera/device/3.5/ICameraDevice.hal b/camera/device/3.5/ICameraDevice.hal
new file mode 100644
index 0000000..e7e8dd3
--- /dev/null
+++ b/camera/device/3.5/ICameraDevice.hal
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.2::CameraMetadata;
+import @3.2::ICameraDevice;
+
+/**
+ * Camera device interface
+ *
+ * Supports the android.hardware.Camera API, and the android.hardware.camera2
+ * API at LIMITED or better hardware level.
+ *
+ */
+interface ICameraDevice extends @3.2::ICameraDevice {
+
+ /**
+ * getPhysicalCameraCharacteristics:
+ *
+ * Return the static camera information for a physical camera ID backing
+ * this logical camera device. This information may not change between consecutive calls.
+ *
+ * Note that HAL must support this function for physical camera IDs that are
+ * not exposed via ICameraProvider::getCameraIdList().
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful query of the camera device characteristics
+ * INTERNAL_ERROR:
+ * The camera device cannot be opened due to an internal
+ * error.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ *
+ * @return cameraCharacteristics
+ * The static metadata for this logical camera device's physical device, or an empty
+ * metadata structure if status is not OK.
+ *
+ */
+ getPhysicalCameraCharacteristics(string physicalCameraId)
+ generates (Status status, CameraMetadata cameraCharacteristics);
+
+};
diff --git a/camera/device/3.5/ICameraDeviceCallback.hal b/camera/device/3.5/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..aa4ad22
--- /dev/null
+++ b/camera/device/3.5/ICameraDeviceCallback.hal
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import @3.2::StreamBuffer;
+import @3.4::ICameraDeviceCallback;
+
+/**
+ * Callback methods for the HAL to call into the framework.
+ */
+interface ICameraDeviceCallback extends @3.4::ICameraDeviceCallback {
+
+ /**
+ * requestStreamBuffers:
+ *
+ * Synchronous callback for HAL to ask for output buffers from camera service.
+ *
+ * This call may be serialized in camera service so it is strongly
+ * recommended to only call this method from one thread.
+ *
+ * When camera device advertises
+ * (CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion ==
+ * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5), HAL
+ * can use this method to request buffers from camera service.
+ *
+ * @return status Status code for the operation, one of:
+ * OK: all requested buffers are returned
+ * FAILED_PARTIAL: some streams failed while some succeeds. Check
+ * individual StreamBufferRet for details.
+ * FAILED_CONFIGURING: the request failed because camera servicve is
+ * performing configureStreams and no buffers are returned.
+ * FAILED_UNKNOWN: the request failed for unknown reason and no buffers
+ * are returned.
+ *
+ * Performance requirements:
+ * This is a blocking call that takes more time with more buffers requested.
+ * HAL must not request large amount of buffers on a latency critical code
+ * path. It is highly recommended to use a dedicated thread to perform
+ * all requestStreamBuffers calls, and adjust the thread priority and/or
+ * timing of making the call in order for buffers to arrive before HAL is
+ * ready to fill the buffer.
+ */
+ requestStreamBuffers(vec<BufferRequest> bufReqs)
+ generates (BufferRequestStatus st, vec<StreamBufferRet> buffers);
+
+ /**
+ * returnStreamBuffers:
+ *
+ * Synchronous callback for HAL to return output buffers to camera service.
+ *
+ * If this method is called during a configureStreams call, it must be blocked
+ * until camera service finishes the ongoing configureStreams call.
+ */
+ returnStreamBuffers(vec<StreamBuffer> buffers);
+
+};
diff --git a/camera/device/3.5/ICameraDeviceSession.hal b/camera/device/3.5/ICameraDeviceSession.hal
new file mode 100644
index 0000000..b2b71cd
--- /dev/null
+++ b/camera/device/3.5/ICameraDeviceSession.hal
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.4::ICameraDeviceSession;
+import @3.4::HalStreamConfiguration;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.4::ICameraDeviceSession {
+
+ /**
+ * configureStreams_3_5:
+ *
+ * Identical to @3.4::ICameraDeviceSession.configureStreams, except that:
+ *
+ * - a streamConfigCounter counter is provided to check for race condition
+ * between configureStreams_3_5 and signalStreamFlush call.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On successful stream configuration.
+ * INTERNAL_ERROR:
+ * If there has been a fatal error and the device is no longer
+ * operational. Only close() can be called successfully by the
+ * framework after this error is returned.
+ * ILLEGAL_ARGUMENT:
+ * If the requested stream configuration is invalid. Some examples
+ * of invalid stream configurations include:
+ * - Including more than 1 INPUT stream
+ * - Not including any OUTPUT streams
+ * - Including streams with unsupported formats, or an unsupported
+ * size for that format.
+ * - Including too many output streams of a certain format.
+ * - Unsupported rotation configuration
+ * - Stream sizes/formats don't satisfy the
+ * StreamConfigurationMode requirements
+ * for non-NORMAL mode, or the requested operation_mode is not
+ * supported by the HAL.
+ * - Unsupported usage flag
+ * The camera service cannot filter out all possible illegal stream
+ * configurations, since some devices may support more simultaneous
+ * streams or larger stream resolutions than the minimum required
+ * for a given camera device hardware level. The HAL must return an
+ * ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+ * ready to accept a future valid stream configuration in a later
+ * configureStreams call.
+ * @return halConfiguration The stream parameters desired by the HAL for
+ * each stream, including maximum buffers, the usage flags, and the
+ * override format.
+ */
+ configureStreams_3_5(@3.5::StreamConfiguration requestedConfiguration)
+ generates (Status status,
+ @3.4::HalStreamConfiguration halConfiguration);
+
+
+ /**
+ * signalStreamFlush:
+ *
+ * Signaling HAL camera service is about to perform configureStreams_3_5 and
+ * HAL must return all buffers of designated streams. HAL must finish
+ * inflight requests normally and return all buffers that belongs to the
+ * designated streams through processCaptureResult or returnStreamBuffer
+ * API in a timely manner, or camera service will run into a fatal error.
+ *
+ * Note that this call serves as an optional hint and camera service may
+ * skip sending this call if all buffers are already returned.
+ *
+ * @param streamIds The ID of streams camera service need all of its
+ * buffers returned.
+ *
+ * @param streamConfigCounter Note that due to concurrency nature, it is
+ * possible the signalStreamFlush call arrives later than the
+ * corresponding configureStreams_3_5 call, HAL must check
+ * streamConfigCounter for such race condition. If the counter is less
+ * than the counter in the last configureStreams_3_5 call HAL last
+ * received, the call is stale and HAL should just return this call.
+ */
+ oneway signalStreamFlush(
+ vec<int32_t> streamIds,
+ uint32_t streamConfigCounter
+ );
+};
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
new file mode 100644
index 0000000..09cf3a4
--- /dev/null
+++ b/camera/device/3.5/default/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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.
+//
+
+cc_library_headers {
+ name: "camera.device@3.5-impl_headers",
+ vendor: true,
+ export_include_dirs: ["include/device_v3_5_impl"]
+}
+
+cc_library_shared {
+ name: "camera.device@3.5-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ vendor: true,
+ srcs: [
+ "CameraDevice.cpp",
+ "CameraDeviceSession.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "libcutils",
+ "camera.device@3.2-impl",
+ "camera.device@3.3-impl",
+ "camera.device@3.4-impl",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.graphics.mapper@2.0",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ local_include_dirs: ["include/device_v3_5_impl"],
+}
diff --git a/camera/device/3.5/default/CameraDevice.cpp b/camera/device/3.5/default/CameraDevice.cpp
new file mode 100644
index 0000000..c5d6c57
--- /dev/null
+++ b/camera/device/3.5/default/CameraDevice.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "CamDev@3.5-impl"
+#include <log/log.h>
+
+#include "CameraModule.h"
+#include "CameraDevice_3_5.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+
+CameraDevice::CameraDevice(sp<CameraModule> module, const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+ V3_4::implementation::CameraDevice(module, cameraId, cameraDeviceNames) {
+}
+
+CameraDevice::~CameraDevice() {
+}
+
+sp<V3_2::implementation::CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device,
+ const camera_metadata_t* deviceInfo,
+ const sp<V3_2::ICameraDeviceCallback>& callback) {
+ sp<CameraDeviceSession> session = new CameraDeviceSession(device, deviceInfo, callback);
+ IF_ALOGV() {
+ session->getInterface()->interfaceChain([](
+ ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+ ALOGV("Session interface chain:");
+ for (auto iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+ return session;
+}
+
+Return<void> CameraDevice::getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+ V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraMetadata cameraCharacteristics;
+ if (status == Status::OK) {
+ // Require module 2.5+ version.
+ if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_5) {
+ ALOGE("%s: get_physical_camera_info must be called on camera module 2.5 or newer",
+ __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ } else {
+ char *end;
+ errno = 0;
+ long id = strtol(physicalCameraId.c_str(), &end, 0);
+ if (id > INT_MAX || (errno == ERANGE && id == LONG_MAX) ||
+ id < INT_MIN || (errno == ERANGE && id == LONG_MIN) ||
+ *end != '\0') {
+ ALOGE("%s: Invalid physicalCameraId %s", __FUNCTION__, physicalCameraId.c_str());
+ status = Status::ILLEGAL_ARGUMENT;
+ } else {
+ camera_metadata_t *physicalInfo = nullptr;
+ int ret = mModule->getPhysicalCameraInfo((int)id, &physicalInfo);
+ if (ret == OK) {
+ V3_2::implementation::convertToHidl(physicalInfo, &cameraCharacteristics);
+ } else {
+ ALOGE("%s: Failed to get physical camera %s info: %s (%d)!", __FUNCTION__,
+ physicalCameraId.c_str(), strerror(-ret), ret);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ }
+ }
+ _hidl_cb(status, cameraCharacteristics);
+ return Void();
+}
+
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+} // namespace V3_5
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..5336ca9
--- /dev/null
+++ b/camera/device/3.5/default/CameraDeviceSession.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "CamDevSession@3.5-impl"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "CameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+CameraDeviceSession::CameraDeviceSession(
+ camera3_device_t* device,
+ const camera_metadata_t* deviceInfo,
+ const sp<V3_2::ICameraDeviceCallback>& callback) :
+ V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) {
+
+ mHasCallback_3_5 = false;
+
+ auto castResult = ICameraDeviceCallback::castFrom(callback);
+ if (castResult.isOk()) {
+ sp<ICameraDeviceCallback> callback3_5 = castResult;
+ if (callback3_5 != nullptr) {
+ mHasCallback_3_5 = true;
+ }
+ }
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+}
+
+Return<void> CameraDeviceSession::configureStreams_3_5(
+ const StreamConfiguration& /*requestedConfiguration*/,
+ ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) {
+ HalStreamConfiguration outStreams;
+ _hidl_cb(Status::OPERATION_NOT_SUPPORTED, outStreams);
+ return Void();
+}
+
+Return<void> CameraDeviceSession::signalStreamFlush(
+ const hidl_vec<int32_t>& /*requests*/, uint32_t /*streamConfigCounter*/) {
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V3_5
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
new file mode 100644
index 0000000..ec34769
--- /dev/null
+++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
@@ -0,0 +1,157 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <../../3.4/default/include/device_v3_4_impl/CameraDeviceSession.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraDeviceSession : public V3_4::implementation::CameraDeviceSession {
+
+ CameraDeviceSession(camera3_device_t*,
+ const camera_metadata_t* deviceInfo,
+ const sp<V3_2::ICameraDeviceCallback>&);
+ virtual ~CameraDeviceSession();
+
+ virtual sp<V3_2::ICameraDeviceSession> getInterface() override {
+ return new TrampolineSessionInterface_3_5(this);
+ }
+
+protected:
+ // Methods from v3.4 and earlier will trampoline to inherited implementation
+ Return<void> configureStreams_3_5(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb);
+
+ Return<void> signalStreamFlush(
+ const hidl_vec<int32_t>& requests,
+ uint32_t streamConfigCounter);
+
+
+ // Whether this camera device session is created with version 3.5 callback.
+ bool mHasCallback_3_5;
+
+private:
+
+ struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession {
+ TrampolineSessionInterface_3_5(sp<CameraDeviceSession> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> constructDefaultRequestSettings(
+ V3_2::RequestTemplate type,
+ V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+ return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams(
+ const V3_2::StreamConfiguration& requestedConfiguration,
+ V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+ return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> processCaptureRequest_3_4(
+ const hidl_vec<V3_4::CaptureRequest>& requests,
+ const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+ ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+ return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+ }
+
+ virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+ const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+ V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+ return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+ }
+
+ virtual Return<void> getCaptureRequestMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<Status> flush() override {
+ return mParent->flush();
+ }
+
+ virtual Return<void> close() override {
+ return mParent->close();
+ }
+
+ virtual Return<void> configureStreams_3_3(
+ const V3_2::StreamConfiguration& requestedConfiguration,
+ configureStreams_3_3_cb _hidl_cb) override {
+ return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_4(
+ const V3_4::StreamConfiguration& requestedConfiguration,
+ configureStreams_3_4_cb _hidl_cb) override {
+ return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> configureStreams_3_5(
+ const StreamConfiguration& requestedConfiguration,
+ configureStreams_3_5_cb _hidl_cb) override {
+ return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+ }
+
+ virtual Return<void> signalStreamFlush(
+ const hidl_vec<int32_t>& requests,
+ uint32_t streamConfigCounter) override {
+ return mParent->signalStreamFlush(requests, streamConfigCounter);
+ }
+
+ private:
+ sp<CameraDeviceSession> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_5
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
new file mode 100644
index 0000000..6bdc60f
--- /dev/null
+++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
@@ -0,0 +1,111 @@
+/*
+ * 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H
+
+#include "CameraDeviceSession.h"
+#include <../../../../3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h>
+
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_string;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::sp;
+
+struct CameraDevice : public V3_4::implementation::CameraDevice {
+ // Called by provider HAL.
+ // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+ // be multiple CameraDevice trying to access the same physical camera. Also, provider will have
+ // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+ // camera is detached.
+ // Delegates nearly all work to CameraDevice_3_4
+ CameraDevice(sp<CameraModule> module,
+ const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+ virtual ~CameraDevice();
+
+ virtual sp<V3_2::ICameraDevice> getInterface() override {
+ return new TrampolineDeviceInterface_3_5(this);
+ }
+
+protected:
+ virtual sp<V3_2::implementation::CameraDeviceSession> createSession(camera3_device_t*,
+ const camera_metadata_t* deviceInfo,
+ const sp<V3_2::ICameraDeviceCallback>&) override;
+
+ Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+ V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb);
+
+private:
+ struct TrampolineDeviceInterface_3_5 : public ICameraDevice {
+ TrampolineDeviceInterface_3_5(sp<CameraDevice> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+ override {
+ return mParent->getResourceCost(_hidl_cb);
+ }
+
+ virtual Return<void> getCameraCharacteristics(
+ V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+ return mParent->getCameraCharacteristics(_hidl_cb);
+ }
+
+ virtual Return<Status> setTorchMode(TorchMode mode) override {
+ return mParent->setTorchMode(mode);
+ }
+
+ virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+ V3_2::ICameraDevice::open_cb _hidl_cb) override {
+ return mParent->open(callback, _hidl_cb);
+ }
+
+ virtual Return<void> dumpState(const hidl_handle& fd) override {
+ return mParent->dumpState(fd);
+ }
+
+ virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+ V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
+ return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
+ }
+ private:
+ sp<CameraDevice> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_5
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H
diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal
new file mode 100644
index 0000000..613187d
--- /dev/null
+++ b/camera/device/3.5/types.hal
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import @3.2::StreamBuffer;
+import @3.4::StreamConfiguration;
+
+/**
+ * StreamConfiguration:
+ *
+ * Identical to @3.4::StreamConfiguration, except that it contains streamConfigCounter
+ */
+struct StreamConfiguration {
+ @3.4::StreamConfiguration v3_4;
+
+ /**
+ * An incrementing counter used for HAL to keep track of the stream
+ * configuration and the paired oneway signalStreamFlush call. When the
+ * counter in signalStreamFlush call is less than the counter here, that
+ * signalStreamFlush call is stale.
+ */
+ uint32_t streamConfigCounter;
+};
+
+enum StreamBufferRequestError : uint32_t {
+ /**
+ * Get buffer failed due to timeout waiting for an available buffer. This is
+ * likely due to the client application holding too many buffers, or the
+ * system is under memory pressure.
+ * This is not a fatal error. HAL may try to request buffer for this stream
+ * later. If HAL cannot get a buffer for certain capture request in time
+ * due to this error, HAL can send an ERROR_REQUEST to camera service and
+ * drop processing that request.
+ */
+ NO_BUFFER_AVAILABLE = 1,
+
+ /**
+ * Get buffer failed due to HAL has reached its maxBuffer count. This is not
+ * a fatal error. HAL may try to request buffer for this stream again after
+ * it returns at least one buffer of that stream to camera service.
+ */
+ MAX_BUFFER_EXCEEDED = 2,
+
+ /**
+ * Get buffer failed due to the stream is disconnected by client
+ * application, has been removed, or not recognized by camera service.
+ * This means application is no longer interested in this stream.
+ * Requesting buffer for this stream must never succeed after this error is
+ * returned. HAL must safely return all buffers of this stream after
+ * getting this error. If HAL gets another capture request later targeting
+ * a disconnected stream, HAL must send an ERROR_REQUEST to camera service
+ * and drop processing that request.
+ */
+ STREAM_DISCONNECTED = 3,
+
+ /**
+ * Get buffer failed for unknown reasons. This is a fatal error and HAL must
+ * send ERROR_DEVICE to camera service and be ready to be closed.
+ */
+ UNKNOWN_ERROR = 4
+};
+
+/**
+ * Per-stream return value for requestStreamBuffers.
+ * For each stream, either an StreamBufferRequestError error code, or all
+ * requested buffers for this stream is returned, so buffers.size() must be
+ * equal to BufferRequest::numBuffersRequested of corresponding stream.
+ */
+safe_union StreamBuffersVal {
+ StreamBufferRequestError error;
+ vec<@3.2::StreamBuffer> buffers;
+};
+
+struct StreamBufferRet {
+ int32_t streamId;
+ StreamBuffersVal val;
+};
+
+enum BufferRequestStatus : uint32_t {
+ /**
+ * Method call succeeded and all requested buffers are returned.
+ */
+ OK = 0,
+
+ /**
+ * Method call failed for some streams. Check per stream status for each
+ * returned StreamBufferRet.
+ */
+ FAILED_PARTIAL = 1,
+
+ /**
+ * Method call failed for all streams and no buffers are returned at all.
+ * Camera service is about to or is performing configureStreams. HAL must
+ * wait until next configureStreams call is finished before requesting
+ * buffers again.
+ */
+ FAILED_CONFIGURING = 2,
+
+ /**
+ * Method call failed for all streams and no buffers are returned at all.
+ * Failure due to bad BufferRequest input, eg: unknown streamId or repeated
+ * streamId.
+ */
+ FAILED_ILLEGAL_ARGUMENTS = 3,
+
+ /**
+ * Method call failed for all streams and no buffers are returned at all.
+ * Failure due to unknown reason.
+ */
+ FAILED_UNKNOWN = 4,
+};
+
+struct BufferRequest {
+ int32_t streamId;
+ uint32_t numBuffersRequested;
+};
+
diff --git a/camera/metadata/3.4/Android.bp b/camera/metadata/3.4/Android.bp
new file mode 100644
index 0000000..388df68
--- /dev/null
+++ b/camera/metadata/3.4/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.metadata@3.4",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.metadata@3.2",
+ "android.hardware.camera.metadata@3.3",
+ ],
+ types: [
+ "CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion",
+ "CameraMetadataTag",
+ ],
+ gen_java: true,
+}
+
diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal
new file mode 100644
index 0000000..b228de8
--- /dev/null
+++ b/camera/metadata/3.4/types.hal
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.4;
+
+/* Include definitions from all prior minor HAL metadata revisions */
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.3::CameraMetadataTag {
+ /** android.request.characteristicKeysNeedingPermission [static, int32[], hidden]
+ *
+ * <p>A list of camera characteristics keys that are only available
+ * in case the camera client has camera permission.</p>
+ */
+ ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_REQUEST_END_3_3,
+
+ ANDROID_REQUEST_END_3_4,
+
+ /** android.info.supportedBufferManagementVersion [static, enum, system]
+ *
+ * <p>The version of buffer management API this camera device supports and opts into.</p>
+ */
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_INFO_END_3_3,
+
+ ANDROID_INFO_END_3_4,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.info.supportedBufferManagementVersion enumeration values
+ * @see ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
+ */
+enum CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion : uint32_t {
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5,
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index ae24d78..de02d78 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -14,10 +14,12 @@
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
"camera.device@1.0-impl",
"camera.device@3.2-impl",
"camera.device@3.3-impl",
"camera.device@3.4-impl",
+ "camera.device@3.5-impl",
"camera.device@3.4-external-impl",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.common@1.0",
@@ -31,6 +33,7 @@
],
header_libs: [
"camera.device@3.4-impl_headers",
+ "camera.device@3.5-impl_headers",
"camera.device@3.4-external-impl_headers"
],
static_libs: [
@@ -56,6 +59,7 @@
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.common@1.0",
],
@@ -80,6 +84,7 @@
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.5",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.common@1.0",
],
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index 6313939..488b9af 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -23,6 +23,7 @@
#include "CameraDevice_1_0.h"
#include "CameraDevice_3_3.h"
#include "CameraDevice_3_4.h"
+#include "CameraDevice_3_5.h"
#include <cutils/properties.h>
#include <string.h>
#include <utils/Trace.h>
@@ -43,6 +44,7 @@
const char *kHAL3_2 = "3.2";
const char *kHAL3_3 = "3.3";
const char *kHAL3_4 = "3.4";
+const char *kHAL3_5 = "3.5";
const char *kHAL1_0 = "1.0";
const int kMaxCameraDeviceNameLen = 128;
const int kMaxCameraIdLen = 16;
@@ -250,7 +252,11 @@
int versionMajor = isV1 ? 1 : 3;
int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion;
if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
- versionMinor = 4;
+ if (mModule->getModuleApiVersion() == CAMERA_MODULE_API_VERSION_2_5) {
+ versionMinor = 5;
+ } else {
+ versionMinor = 4;
+ }
}
char deviceName[kMaxCameraDeviceNameLen];
snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s",
@@ -546,63 +552,69 @@
return Void();
}
- sp<android::hardware::camera::device::V3_2::ICameraDevice> device;
- if (deviceVersion == kHAL3_4) {
+ // ICameraDevice 3.4 or upper
+ sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl;
+ if (deviceVersion >= kHAL3_4) {
ALOGV("Constructing v3.4 camera device");
- sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
- new android::hardware::camera::device::V3_4::implementation::CameraDevice(
+ if (deviceVersion == kHAL3_4) {
+ deviceImpl = new android::hardware::camera::device::V3_4::implementation::CameraDevice(
mModule, cameraId, mCameraDeviceNames);
+ } else if (deviceVersion == kHAL3_5) {
+ deviceImpl = new android::hardware::camera::device::V3_5::implementation::CameraDevice(
+ mModule, cameraId, mCameraDeviceNames);
+ }
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
- device = nullptr;
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
-
- device = deviceImpl;
- _hidl_cb (Status::OK, device);
+ IF_ALOGV() {
+ deviceImpl->getInterface()->interfaceChain([](
+ ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+ ALOGV("Device interface chain:");
+ for (auto iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+ _hidl_cb (Status::OK, deviceImpl->getInterface());
return Void();
}
+ // ICameraDevice 3.2 and 3.3
// Since some Treble HAL revisions can map to the same legacy HAL version(s), we default
// to the newest possible Treble HAL revision, but allow for override if needed via
// system property.
switch (mPreferredHal3MinorVersion) {
case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2
ALOGV("Constructing v3.2 camera device");
- sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
- new android::hardware::camera::device::V3_2::implementation::CameraDevice(
+ deviceImpl = new android::hardware::camera::device::V3_2::implementation::CameraDevice(
mModule, cameraId, mCameraDeviceNames);
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
- device = nullptr;
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
- device = deviceImpl;
break;
}
case 3: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.3
ALOGV("Constructing v3.3 camera device");
- sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
- new android::hardware::camera::device::V3_3::implementation::CameraDevice(
+ deviceImpl = new android::hardware::camera::device::V3_3::implementation::CameraDevice(
mModule, cameraId, mCameraDeviceNames);
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
- device = nullptr;
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
- device = deviceImpl;
break;
}
default:
ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
- device = nullptr;
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
- _hidl_cb (Status::OK, device);
+
+ _hidl_cb (Status::OK, deviceImpl->getInterface());
return Void();
}
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 439333d..f2a7836 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -2080,6 +2080,14 @@
} else {
ADD_FAILURE() << "Get camera hardware level failed!";
}
+
+ entry.count = 0;
+ retcode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION, &entry);
+ if ((0 == retcode) || (entry.count > 0)) {
+ ADD_FAILURE() << "ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION "
+ << " per API contract should never be set by Hal!";
+ }
});
ASSERT_TRUE(ret.isOk());
}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 73afb1b..ff5b3e8 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -1,5 +1,13 @@
<compatibility-matrix version="1.0" type="framework" level="4">
<hal format="hidl" optional="false">
+ <name>android.hardware.atrace</name>
+ <version>1.0</version>
+ <interface>
+ <name>IAtraceDevice</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>4.0</version>
<interface>
@@ -216,10 +224,10 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.health.filesystem</name>
+ <name>android.hardware.health.storage</name>
<version>1.0</version>
<interface>
- <name>IFileSystem</name>
+ <name>IStorage</name>
<instance>default</instance>
</interface>
</hal>
diff --git a/configstore/1.0/ISurfaceFlingerConfigs.hal b/configstore/1.0/ISurfaceFlingerConfigs.hal
index 0790905..1de7570 100644
--- a/configstore/1.0/ISurfaceFlingerConfigs.hal
+++ b/configstore/1.0/ISurfaceFlingerConfigs.hal
@@ -61,7 +61,7 @@
hasWideColorDisplay() generates (OptionalBool value);
/**
- * hwHdrDisplay indicates that the device has an High Dynamic Range display.
+ * hwHDRDisplay indicates that the device has an High Dynamic Range display.
* A display is considered High Dynamic Range if it
*
* 1. is a wide color gamut display, typically DCI-P3 or lager
diff --git a/current.txt b/current.txt
index 4e5ec41..4709ab3 100644
--- a/current.txt
+++ b/current.txt
@@ -385,11 +385,15 @@
10ff2fae516346b86121368ce5790d5accdfcb73983246b813f3d488b66db45a android.hardware.wifi.supplicant@1.1::ISupplicantStaNetwork
# ABI preserving changes to HALs during Android Q
+2a55e224aa9bc62c0387cd85ad3c97e33f0c33a4e1489cbae86b2523e6f9df35 android.hardware.camera.device@3.2::ICameraDevice
+f61b616732d8f374e030f90575d7eba3ecc99d209a05b945949ba892bcb81e1d android.hardware.camera.device@3.2::ICameraDeviceSession
+684702a60deef03a1e8093961dc0a18c555c857ad5a77ba7340b0635ae01eb70 android.hardware.camera.device@3.4::ICameraDeviceSession
a95745bbf76aea16a76518bd7efe70cabc5886d09eaeffc993c2e1787a22ed23 android.hardware.camera.metadata@3.3::types
-5f936a5befde7af8d2a683670f80a836b4741e94d84b7b39026da3ed78be9906 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
+da33234403ff5d60f3473711917b9948e6484a4260b5247acdafb111193a9de2 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
+b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice
574e8f1499436fb4075894dcae0b36682427956ecb114f17f1fe22d116a83c6b android.hardware.neuralnetworks@1.0::IPreparedModel
-1a5ae9793223658174258b523763c557abad6fb917df0b8e3cc097fc89035811 android.hardware.neuralnetworks@1.0::types
-4310eb8272f085914952f3bfb73a8f8bb477a80e8b93596f0ea5acb58546b66d android.hardware.neuralnetworks@1.1::types
+1fb32361286b938d48a55c2539c846732afce0b99fe08590f556643125bc13d3 android.hardware.neuralnetworks@1.0::types
+e22e8135d061d0e9c4c1a70c25c19fdba10f4d3cda9795ef25b6392fc520317c android.hardware.neuralnetworks@1.1::types
1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse
271187e261b30c01a33011aea257c07a2d2f05b72943ebee89e973e997849973 android.hardware.radio@1.0::types
1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio
diff --git a/fastboot/1.0/IFastboot.hal b/fastboot/1.0/IFastboot.hal
index 653fd79..a96755e 100644
--- a/fastboot/1.0/IFastboot.hal
+++ b/fastboot/1.0/IFastboot.hal
@@ -29,4 +29,34 @@
* reformatting.
*/
getPartitionType(string partitionName) generates (FileSystemType type, Result result);
+
+ /**
+ * Executes a fastboot OEM command.
+ *
+ * @param oemCmdArgs The oem command that is passed to the fastboot HAL.
+ * @response result Returns the status SUCCESS if the operation is successful,
+ * INVALID_ARGUMENT for bad arguments,
+ * FAILURE_UNKNOWN for an invalid/unsupported command.
+ */
+ doOemCommand(string oemCmd) generates (Result result);
+
+ /**
+ * Returns an OEM-defined string indicating the variant of the device, for
+ * example, US and ROW.
+ *
+ * @response variant Indicates the device variant.
+ * @response result Returns the status SUCCESS if the operation is successful,
+ * FAILURE_UNKNOWN otherwise.
+ */
+ getVariant() generates (string variant, Result result);
+
+ /**
+ * Returns whether off-mode-charging is enabled. If enabled, the device
+ * autoboots into a special mode when power is applied.
+ *
+ * @response state Returns whether off mode charging is enabled.
+ * @response result Returns the status SUCCESS if the operation is successful,
+ * FAILURE_UNKNOWN otherwise.
+ */
+ getOffModeChargeState() generates (bool state, Result result);
};
diff --git a/fastboot/1.0/types.hal b/fastboot/1.0/types.hal
index 8453deb..3fbe639 100644
--- a/fastboot/1.0/types.hal
+++ b/fastboot/1.0/types.hal
@@ -53,9 +53,9 @@
struct Result {
Status status;
/**
- * Error message pertaining to the status. It must be a failure message for
+ * Message pertaining to the status. It must be a failure message for
* Status FAILURE_UNKNOWN/NOT_SUPPORTED or an informative message for
* Status SUCCESS.
*/
- string error;
+ string message;
};
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index c9f840e..2d901f3 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -119,6 +119,11 @@
struct ComparableBlacklistedSource {
IGnssConfiguration::BlacklistedSource id;
+ ComparableBlacklistedSource() {
+ id.constellation = GnssConstellationType::UNKNOWN;
+ id.svid = 0;
+ }
+
bool operator<(const ComparableBlacklistedSource& compare) const {
return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
(id.constellation < compare.id.constellation)));
@@ -191,18 +196,21 @@
* 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does not use those satellites.
* 4a & b) Turns off location, and send in empty blacklist.
- * 5) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does re-use at least the previously strongest satellite
+ * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
+ * formerly strongest satellite
*/
TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
const int kLocationsToAwait = 3;
+ const int kRetriesToUnBlacklist = 10;
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
- kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
/*
* Identify strongest SV seen at least kLocationsToAwait -1 times
@@ -237,13 +245,18 @@
// retry and ensure satellite not used
list_gnss_sv_status_.clear();
- location_called_count_ = 0;
StartAndCheckLocations(kLocationsToAwait);
+ // early exit if test is being run with insufficient signal
+ if (location_called_count_ == 0) {
+ ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+ }
+ ASSERT_TRUE(location_called_count_ > 0);
+
// Tolerate 1 less sv status to handle edge cases in reporting.
EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
- kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
for (const auto& gnss_sv_status : list_gnss_sv_status_) {
for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
@@ -260,28 +273,40 @@
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
- StopAndClearLocations();
- list_gnss_sv_status_.clear();
-
- StartAndCheckLocations(kLocationsToAwait);
-
- // Tolerate 1 less sv status to handle edge cases in reporting.
- EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
- kLocationsToAwait);
-
bool strongest_sv_is_reobserved = false;
- for (const auto& gnss_sv_status : list_gnss_sv_status_) {
- for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
- const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
- if ((gnss_sv.svid == source_to_blacklist.svid) &&
- (gnss_sv.constellation == source_to_blacklist.constellation) &&
- (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
- strongest_sv_is_reobserved = true;
- break;
- }
+ // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
+ int unblacklist_loops_remaining = kRetriesToUnBlacklist;
+ while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
+ StopAndClearLocations();
+ list_gnss_sv_status_.clear();
+
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // early exit loop if test is being run with insufficient signal
+ if (location_called_count_ == 0) {
+ ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
- if (strongest_sv_is_reobserved) break;
+ ASSERT_TRUE(location_called_count_ > 0);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
+ ALOGD(
+ "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
+ ", tries remaining %d",
+ (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
+
+ for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+ for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+ const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+ if ((gnss_sv.svid == source_to_blacklist.svid) &&
+ (gnss_sv.constellation == source_to_blacklist.constellation) &&
+ (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
+ strongest_sv_is_reobserved = true;
+ break;
+ }
+ }
+ if (strongest_sv_is_reobserved) break;
+ }
}
EXPECT_TRUE(strongest_sv_is_reobserved);
StopAndClearLocations();
@@ -304,8 +329,8 @@
// Tolerate 1 less sv status to handle edge cases in reporting.
EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
- kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
// Find first non-GPS constellation to blacklist
GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 1cafafe..250c392 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -311,6 +311,8 @@
ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
reader->parse();
});
+ reader->reset();
+ writer->reset();
}
} // namespace vts
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 8b8c7ae..0a3e88b 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -71,6 +71,7 @@
class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
protected:
void SetUp() override {
+ VtsHalHidlTargetTestBase::SetUp();
ASSERT_NO_FATAL_FAILURE(
mComposer = std::make_unique<Composer>(
GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
@@ -100,6 +101,7 @@
EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
}
+ VtsHalHidlTargetTestBase::TearDown();
}
// returns an invalid display id (one that has not been registered to a
@@ -668,6 +670,11 @@
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+ Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
+ mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+ IComposerClient::Attribute::WIDTH);
+ mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+ IComposerClient::Attribute::HEIGHT);
mWriter = std::make_unique<CommandWriterBase>(1024);
mReader = std::make_unique<TestCommandReader>();
}
@@ -679,12 +686,13 @@
const native_handle_t* allocate() {
IMapper::BufferDescriptorInfo info{};
- info.width = 64;
- info.height = 64;
+ info.width = mDisplayWidth;
+ info.height = mDisplayHeight;
info.layerCount = 1;
info.format = PixelFormat::RGBA_8888;
info.usage =
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY);
return mGralloc->allocate(info);
}
@@ -693,6 +701,8 @@
std::unique_ptr<CommandWriterBase> mWriter;
std::unique_ptr<TestCommandReader> mReader;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
private:
std::unique_ptr<Gralloc> mGralloc;
@@ -779,6 +789,60 @@
}
/**
+ * Test IComposerClient::Command::PRESENT_DISPLAY
+ *
+ * Test that IComposerClient::Command::PRESENT_DISPLAY works without
+ * additional call to validateDisplay when only the layer buffer handle and
+ * surface damage have been set
+ */
+TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
+ mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB);
+
+ auto handle = allocate();
+ ASSERT_NE(nullptr, handle);
+
+ IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+ mWriter->setLayerDisplayFrame(displayFrame);
+ mWriter->setLayerPlaneAlpha(1);
+ mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+ mWriter->setLayerTransform(static_cast<Transform>(0));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, displayFrame));
+ mWriter->setLayerZOrder(10);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame));
+ mWriter->setLayerBuffer(0, handle, -1);
+ mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ GTEST_SUCCEED() << "Composition change requested, skipping test";
+ return;
+ }
+
+ ASSERT_EQ(0, mReader->mErrors.size());
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->selectLayer(layer);
+ auto handle2 = allocate();
+ ASSERT_NE(nullptr, handle2);
+ mWriter->setLayerBuffer(0, handle2, -1);
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10}));
+ mWriter->presentDisplay();
+ execute();
+}
+
+/**
* Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION.
*/
TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index d8fb656..da99460 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -86,6 +86,8 @@
ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
reader->parse();
});
+ reader->reset();
+ writer->reset();
}
Display ComposerClient::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp
index 23061dd..78da099 100644
--- a/graphics/composer/2.3/Android.bp
+++ b/graphics/composer/2.3/Android.bp
@@ -12,6 +12,7 @@
],
interfaces: [
"android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hidl.base@1.0",
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
index 77dd3ee..089438e 100644
--- a/graphics/composer/2.3/IComposerClient.hal
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -16,12 +16,58 @@
package android.hardware.graphics.composer@2.3;
+import android.hardware.graphics.composer@2.1::IComposerClient.Command;
import @2.2::IComposerClient;
import @2.1::Display;
import @2.1::Error;
interface IComposerClient extends @2.2::IComposerClient {
+ enum Command : @2.2::IComposerClient.Command {
+ /**
+ * SET_LAYER_COLOR_TRANSFORM has this pseudo prototype
+ *
+ * setLayerColorTransform(float[16] matrix);
+ *
+ * This command has the following binary layout in bytes:
+ *
+ * 0 - 16 * 4: matrix
+ *
+ * Sets a matrix for color transform which will be applied on this layer
+ * before composition.
+ *
+ * If the device is not capable of apply the matrix on this layer, it must force
+ * this layer to client composition during VALIDATE_DISPLAY.
+ *
+ * The matrix provided is an affine color transformation of the following
+ * form:
+ *
+ * |r.r r.g r.b 0|
+ * |g.r g.g g.b 0|
+ * |b.r b.g b.b 0|
+ * |Tr Tg Tb 1|
+ *
+ * This matrix must be provided in row-major form:
+ *
+ * {r.r, r.g, r.b, 0, g.r, ...}.
+ *
+ * Given a matrix of this form and an input color [R_in, G_in, B_in],
+ * the input color must first be converted to linear space
+ * [R_linear, G_linear, B_linear], then the output linear color
+ * [R_out_linear, G_out_linear, B_out_linear] will be:
+ *
+ * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
+ * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
+ * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
+ *
+ * [R_out_linear, G_out_linear, B_out_linear] must then be converted to
+ * gamma space: [R_out, G_out, B_out] before blending.
+ *
+ * @param matrix is a 4x4 transform matrix (16 floats) as described above.
+ */
+ SET_LAYER_COLOR_TRANSFORM = 0x40d << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+ };
+
/**
* Returns the port and data that describe a physical display. The port is
* a unique number that identifies a physical connector (e.g. eDP, HDMI)
@@ -42,4 +88,29 @@
uint8_t port,
vec<uint8_t> data);
+ /**
+ * Executes commands from the input command message queue. Return values
+ * generated by the input commands are written to the output command
+ * message queue in the form of value commands.
+ *
+ * @param inLength is the length of input commands.
+ * @param inHandles is an array of handles referenced by the input
+ * commands.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_PARAMETER when inLength is not equal to the length of
+ * commands in the input command message queue.
+ * NO_RESOURCES when the output command message queue was not
+ * properly drained.
+ * @param outQueueChanged indicates whether the output command message
+ * queue has changed.
+ * @param outLength is the length of output commands.
+ * @param outHandles is an array of handles referenced by the output
+ * commands.
+ */
+ executeCommands_2_3(uint32_t inLength,
+ vec<handle> inHandles)
+ generates (Error error,
+ bool outQueueChanged,
+ uint32_t outLength,
+ vec<handle> outHandles);
};
diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..c48fe7a
--- /dev/null
+++ b/graphics/composer/2.3/utils/command-buffer/Android.bp
@@ -0,0 +1,15 @@
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.3-command-buffer",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
new file mode 100644
index 0000000..3f7b2c9
--- /dev/null
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_3::IComposerClient;
+
+// This class helps build a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_2::CommandWriterBase {
+ public:
+ CommandWriterBase(uint32_t initialMaxSize) : V2_2::CommandWriterBase(initialMaxSize) {}
+
+ static constexpr uint16_t kSetLayerColorTransformLength = 16;
+ void setLayerColorTransform(const float* matrix) {
+ beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
+ kSetLayerColorTransformLength);
+ for (int i = 0; i < 16; i++) {
+ writeFloat(matrix[i]);
+ }
+ endCommand();
+ }
+
+ protected:
+ void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
+ V2_2::CommandWriterBase::beginCommand_2_2(
+ static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+ }
+};
+
+// This class helps parse a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_2::CommandReaderBase {
+ public:
+ CommandReaderBase() : V2_2::CommandReaderBase(){};
+};
+
+} // namespace V2_3
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.3/utils/hal/Android.bp b/graphics/composer/2.3/utils/hal/Android.bp
index aa46df1..3ee9300 100644
--- a/graphics/composer/2.3/utils/hal/Android.bp
+++ b/graphics/composer/2.3/utils/hal/Android.bp
@@ -26,9 +26,11 @@
],
header_libs: [
"android.hardware.graphics.composer@2.2-hal",
+ "android.hardware.graphics.composer@2.3-command-buffer",
],
export_header_lib_headers: [
"android.hardware.graphics.composer@2.2-hal",
+ "android.hardware.graphics.composer@2.3-command-buffer",
],
export_include_dirs: ["include"],
}
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index e717d84..c805472 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -22,6 +22,7 @@
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.3/ComposerCommandEngine.h>
#include <composer-hal/2.3/ComposerHal.h>
namespace android {
@@ -55,10 +56,27 @@
return Void();
}
+ Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
+ IComposerClient::executeCommands_2_2_cb hidl_cb) override {
+ std::lock_guard<std::mutex> lock(mCommandEngineMutex);
+ bool outChanged = false;
+ uint32_t outLength = 0;
+ hidl_vec<hidl_handle> outHandles;
+ Error error =
+ mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles);
+
+ hidl_cb(error, outChanged, outLength, outHandles);
+
+ mCommandEngine->reset();
+
+ return Void();
+ }
+
private:
using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
-
+ using BaseType2_1::mCommandEngine;
+ using BaseType2_1::mCommandEngineMutex;
using BaseType2_1::mHal;
};
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
new file mode 100644
index 0000000..c3dcbcd
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine {
+ public:
+ ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
+ : BaseType2_2(hal, resources), mHal(hal) {}
+
+ protected:
+ bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+ switch (static_cast<IComposerClient::Command>(command)) {
+ case IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM:
+ return executeSetLayerColorTransform(length);
+ default:
+ return BaseType2_2::executeCommand(command, length);
+ }
+ }
+
+ bool executeSetLayerColorTransform(uint16_t length) {
+ if (length != CommandWriterBase::kSetLayerColorTransformLength) {
+ return false;
+ }
+
+ float matrix[16];
+ for (int i = 0; i < 16; i++) {
+ matrix[i] = readFloat();
+ }
+ auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+ }
+
+ private:
+ using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+ using BaseType2_1::mWriter;
+ using BaseType2_2 = V2_2::hal::ComposerCommandEngine;
+
+ ComposerHal* mHal;
+};
+
+} // namespace hal
+} // namespace V2_3
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
index 37ea0a3..0f6205a 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -27,11 +27,13 @@
using V2_1::Display;
using V2_1::Error;
+using V2_1::Layer;
class ComposerHal : public V2_2::hal::ComposerHal {
public:
virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData) = 0;
+ virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index 53f2d1b..ed1878b 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -66,6 +66,14 @@
return Error::NONE;
}
+ Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override {
+ if (!mDispatch.setLayerColorTransform) {
+ return Error::UNSUPPORTED;
+ }
+ int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix);
+ return static_cast<Error>(err);
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_2::initDispatch()) {
@@ -74,12 +82,15 @@
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
&mDispatch.getDisplayIdentificationData);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
+ &mDispatch.setLayerColorTransform);
return true;
}
private:
struct {
HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
+ HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
} mDispatch = {};
using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 0553258..19438cb 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -31,6 +31,7 @@
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
],
cflags: [
"-O0",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index df696c9..7548cb5 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -40,5 +40,6 @@
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
],
}
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index f4e34f0..1030ddc 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -20,7 +20,9 @@
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.3/ComposerVts.h>
namespace android {
@@ -65,6 +67,9 @@
// explicitly disable vsync
mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
mComposerCallback->setVsyncAllowed(false);
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
}
void TearDown() override {
@@ -75,11 +80,18 @@
}
}
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ // use the slot count usually set by SF
+ static constexpr uint32_t kBufferSlotCount = 64;
+
std::unique_ptr<Composer> mComposer;
std::unique_ptr<ComposerClient> mComposerClient;
sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
// the first display and is assumed never to be removed
Display mPrimaryDisplay;
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
private:
Display waitForFirstDisplay() {
@@ -115,6 +127,31 @@
}
}
+/**
+ * Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM.
+ * TODO Add color to the layer, use matrix to keep only red component,
+ * and check.
+ */
+TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(layer =
+ mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+
+ // clang-format off
+ const std::array<float, 16> matrix = {{
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ }};
+ // clang-format on
+
+ mWriter->setLayerColorTransform(matrix.data());
+ execute();
+}
+
} // namespace
} // namespace vts
} // namespace V2_3
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index 6d3be99..e02bfa9 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -142,7 +142,7 @@
Return<Result> Health::update() {
if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {
LOG(WARNING) << "health@2.0: update: not initialized. "
- << "update() should not be called in charger / recovery.";
+ << "update() should not be called in charger";
return Result::UNKNOWN;
}
diff --git a/health/2.0/default/HealthImplDefault.cpp b/health/2.0/default/HealthImplDefault.cpp
index 15346bf..e3cbefd 100644
--- a/health/2.0/default/HealthImplDefault.cpp
+++ b/health/2.0/default/HealthImplDefault.cpp
@@ -46,9 +46,32 @@
return 0;
}
+void healthd_mode_default_impl_init(struct healthd_config*) {
+ // noop
+}
+
+int healthd_mode_default_impl_preparetowait(void) {
+ return -1;
+}
+
+void healthd_mode_default_impl_heartbeat(void) {
+ // noop
+}
+
+void healthd_mode_default_impl_battery_update(struct android::BatteryProperties*) {
+ // noop
+}
+
+static struct healthd_mode_ops healthd_mode_default_impl_ops = {
+ .init = healthd_mode_default_impl_init,
+ .preparetowait = healthd_mode_default_impl_preparetowait,
+ .heartbeat = healthd_mode_default_impl_heartbeat,
+ .battery_update = healthd_mode_default_impl_battery_update,
+};
+
extern "C" IHealth* HIDL_FETCH_IHealth(const char* name) {
const static std::string providedInstance{"backup"};
-
+ healthd_mode_ops = &healthd_mode_default_impl_ops;
if (providedInstance == name) {
// use defaults
// Health class stores static instance
diff --git a/health/filesystem/1.0/Android.bp b/health/storage/1.0/Android.bp
similarity index 72%
rename from health/filesystem/1.0/Android.bp
rename to health/storage/1.0/Android.bp
index 74b9bc3..35ee34f 100644
--- a/health/filesystem/1.0/Android.bp
+++ b/health/storage/1.0/Android.bp
@@ -1,14 +1,15 @@
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
- name: "android.hardware.health.filesystem@1.0",
+ name: "android.hardware.health.storage@1.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"types.hal",
- "IFileSystem.hal",
+ "IGarbageCollectCallback.hal",
+ "IStorage.hal",
],
interfaces: [
"android.hidl.base@1.0",
diff --git a/health/filesystem/1.0/IFileSystem.hal b/health/storage/1.0/IGarbageCollectCallback.hal
similarity index 63%
rename from health/filesystem/1.0/IFileSystem.hal
rename to health/storage/1.0/IGarbageCollectCallback.hal
index 33ea3ff..2c24ead 100644
--- a/health/filesystem/1.0/IFileSystem.hal
+++ b/health/storage/1.0/IGarbageCollectCallback.hal
@@ -13,21 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package android.hardware.health.filesystem@1.0;
+package android.hardware.health.storage@1.0;
/**
- * IFileSystem is an interface that provides operations on underlying storage
- * devices, including flash memory.
+ * Callback interface to IStorage.garbageCollect.
*/
-interface IFileSystem {
+interface IGarbageCollectCallback {
/**
- * Start garbage collection on the driver of storage devices. This function
- * must be called at regular intervals when it is a good time for a
- * longer-running cleanup tasks.
+ * When garbage collection has finished, the implementation must
+ * invoke this function to indicate the result of the garbage collection.
*
* @return result Execution result. See documentation for Result for
* details.
*/
- garbageCollect() generates (Result result);
+ oneway onFinish(Result result);
};
diff --git a/health/storage/1.0/IStorage.hal b/health/storage/1.0/IStorage.hal
new file mode 100644
index 0000000..980cf45
--- /dev/null
+++ b/health/storage/1.0/IStorage.hal
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package android.hardware.health.storage@1.0;
+
+import IGarbageCollectCallback;
+
+/**
+ * IStorage is an interface that provides operations on underlying storage
+ * devices, including flash memory.
+ */
+interface IStorage {
+ /**
+ * Start garbage collection on the driver of storage devices.
+ *
+ * Garbage collection must be started at regular intervals when it is a good
+ * time for a longer-running cleanup tasks, roughly daily.
+ *
+ * When garbage collection finishes or encounters an error before the
+ * specified timeout, the implementation must call IGarbageCollect.finish
+ * immediately with appropriate result.
+ *
+ * If garbage collection does not finish within the specified timeout,
+ * the implementation must stop garbage collection, and must not call
+ * IGarbageCollect.finish.
+ *
+ * @param timeoutSeconds timeout in seconds. The implementation must
+ * return after the timeout is reached.
+ *
+ * @param callback callback interface. Callback must be null if the client
+ * does not need to receive any callbacks.
+ *
+ */
+ oneway garbageCollect(uint64_t timeoutSeconds,
+ IGarbageCollectCallback callback);
+};
diff --git a/health/storage/1.0/default/Android.bp b/health/storage/1.0/default/Android.bp
new file mode 100644
index 0000000..4723443
--- /dev/null
+++ b/health/storage/1.0/default/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+cc_binary {
+ name: "android.hardware.health.storage@1.0-service",
+ vendor: true,
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.health.storage@1.0-service.rc"],
+ srcs: [
+ "Storage.cpp",
+ "service.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "android.hardware.health.storage@1.0",
+ ],
+
+ static_libs: [
+ "libfstab",
+ ],
+
+ vintf_fragments: [
+ "manifest_android.hardware.health.storage@1.0.xml",
+ ],
+}
diff --git a/health/storage/1.0/default/Storage.cpp b/health/storage/1.0/default/Storage.cpp
new file mode 100644
index 0000000..2e53c50
--- /dev/null
+++ b/health/storage/1.0/default/Storage.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#include "Storage.h"
+
+#include <sstream>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <fstab/fstab.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace storage {
+namespace V1_0 {
+namespace implementation {
+
+using base::ReadFileToString;
+using base::Timer;
+using base::Trim;
+using base::WriteStringToFd;
+using base::WriteStringToFile;
+
+std::string getGarbageCollectPath() {
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ struct fstab_rec* rec = NULL;
+
+ for (int i = 0; i < fstab->num_entries; i++) {
+ if (fs_mgr_has_sysfs_path(&fstab->recs[i])) {
+ rec = &fstab->recs[i];
+ break;
+ }
+ }
+ if (!rec) {
+ return "";
+ }
+
+ std::string path;
+ path.append(rec->sysfs_path);
+ path = path + "/manual_gc";
+
+ return path;
+}
+
+Return<void> Storage::garbageCollect(uint64_t timeoutSeconds,
+ const sp<IGarbageCollectCallback>& cb) {
+ Result result = Result::SUCCESS;
+ std::string path = getGarbageCollectPath();
+
+ if (path.empty()) {
+ LOG(WARNING) << "Cannot find Dev GC path";
+ result = Result::UNKNOWN_ERROR;
+ } else {
+ Timer timer;
+ LOG(INFO) << "Start Dev GC on " << path;
+ while (1) {
+ std::string require;
+ if (!ReadFileToString(path, &require)) {
+ PLOG(WARNING) << "Reading manual_gc failed in " << path;
+ result = Result::IO_ERROR;
+ break;
+ }
+ require = Trim(require);
+ if (require == "" || require == "off" || require == "disabled") {
+ LOG(DEBUG) << "No more to do Dev GC";
+ break;
+ }
+ LOG(DEBUG) << "Trigger Dev GC on " << path;
+ if (!WriteStringToFile("1", path)) {
+ PLOG(WARNING) << "Start Dev GC failed on " << path;
+ result = Result::IO_ERROR;
+ break;
+ }
+ if (timer.duration() >= std::chrono::seconds(timeoutSeconds)) {
+ LOG(WARNING) << "Dev GC timeout";
+ // Timeout is not treated as an error. Try next time.
+ break;
+ }
+ sleep(2);
+ }
+ LOG(INFO) << "Stop Dev GC on " << path;
+ if (!WriteStringToFile("0", path)) {
+ PLOG(WARNING) << "Stop Dev GC failed on " << path;
+ result = Result::IO_ERROR;
+ }
+ }
+
+ if (cb != nullptr) {
+ auto ret = cb->onFinish(result);
+ if (!ret.isOk()) {
+ LOG(WARNING) << "Cannot return result to callback: " << ret.description();
+ }
+ }
+ return Void();
+}
+
+Return<void> Storage::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+ if (handle == nullptr || handle->numFds < 1) {
+ return Void();
+ }
+
+ int fd = handle->data[0];
+ std::stringstream output;
+
+ std::string path = getGarbageCollectPath();
+ if (path.empty()) {
+ output << "Cannot find Dev GC path";
+ } else {
+ std::string require;
+
+ if (ReadFileToString(path, &require)) {
+ output << path << ":" << require << std::endl;
+ }
+
+ if (WriteStringToFile("0", path)) {
+ output << "stop success" << std::endl;
+ }
+ }
+
+ if (!WriteStringToFd(output.str(), fd)) {
+ PLOG(WARNING) << "debug: cannot write to fd";
+ }
+
+ fsync(fd);
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace storage
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/storage/1.0/default/Storage.h b/health/storage/1.0/default/Storage.h
new file mode 100644
index 0000000..8c57ddb
--- /dev/null
+++ b/health/storage/1.0/default/Storage.h
@@ -0,0 +1,49 @@
+/*
+ * 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 ANDROID_HARDWARE_HEALTH_FILESYSTEM_V1_0_FILESYSTEM_H
+#define ANDROID_HARDWARE_HEALTH_FILESYSTEM_V1_0_FILESYSTEM_H
+
+#include <android/hardware/health/storage/1.0/IStorage.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace storage {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+struct Storage : public IStorage {
+ Return<void> garbageCollect(uint64_t timeoutSeconds,
+ const sp<IGarbageCollectCallback>& cb) override;
+ Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace storage
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_HEALTH_FILESYSTEM_V1_0_FILESYSTEM_H
diff --git a/health/storage/1.0/default/android.hardware.health.storage@1.0-service.rc b/health/storage/1.0/default/android.hardware.health.storage@1.0-service.rc
new file mode 100644
index 0000000..c6a1425
--- /dev/null
+++ b/health/storage/1.0/default/android.hardware.health.storage@1.0-service.rc
@@ -0,0 +1,5 @@
+service vendor.health-storage-hal-1-0 /vendor/bin/hw/android.hardware.health.storage@1.0-service
+ interface android.hardware.health.storage@1.0::IStorage default
+ class hal
+ user system
+ group system
diff --git a/health/storage/1.0/default/manifest_android.hardware.health.storage@1.0.xml b/health/storage/1.0/default/manifest_android.hardware.health.storage@1.0.xml
new file mode 100644
index 0000000..ffe854e
--- /dev/null
+++ b/health/storage/1.0/default/manifest_android.hardware.health.storage@1.0.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal>
+ <name>android.hardware.health.storage</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IStorage</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/health/storage/1.0/default/service.cpp b/health/storage/1.0/default/service.cpp
new file mode 100644
index 0000000..a945033
--- /dev/null
+++ b/health/storage/1.0/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright 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.
+ */
+
+#include <hidl/HidlTransportSupport.h>
+#include "Storage.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::UNKNOWN_ERROR;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::health::storage::V1_0::IStorage;
+using android::hardware::health::storage::V1_0::implementation::Storage;
+
+int main() {
+ configureRpcThreadpool(1, true);
+
+ sp<IStorage> service = new Storage();
+ status_t result = service->registerAsService();
+
+ if (result != OK) {
+ return result;
+ }
+
+ joinRpcThreadpool();
+ return UNKNOWN_ERROR;
+}
diff --git a/health/filesystem/1.0/types.hal b/health/storage/1.0/types.hal
similarity index 88%
rename from health/filesystem/1.0/types.hal
rename to health/storage/1.0/types.hal
index 00431f7..2da0871 100644
--- a/health/filesystem/1.0/types.hal
+++ b/health/storage/1.0/types.hal
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.health.filesystem@1.0;
+package android.hardware.health.storage@1.0;
/**
* Status values for HAL methods.
@@ -25,10 +25,6 @@
*/
SUCCESS = 0,
/**
- * Execution of the method timed out.
- */
- TIMEOUT,
- /**
* An IO error is encountered when the HAL communicates with the device.
*/
IO_ERROR,
diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..63591cf
--- /dev/null
+++ b/health/storage/1.0/vts/functional/Android.bp
@@ -0,0 +1,26 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalHealthStorageV1_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalHealthStorageV1_0TargetTest.cpp"],
+ static_libs: ["android.hardware.health.storage@1.0"],
+ shared_libs: [
+ "libhidltransport"
+ ],
+}
+
diff --git a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
new file mode 100644
index 0000000..5ad561c
--- /dev/null
+++ b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/health/storage/1.0/IStorage.h>
+#include <hidl/HidlTransportSupport.h>
+#include <unistd.h>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace storage {
+namespace V1_0 {
+
+using ::std::literals::chrono_literals::operator""ms;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) << ret.description()
+
+// Dev GC timeout. This is the timeout used by vold.
+const uint64_t kDevGcTimeoutSec = 120;
+const std::chrono::seconds kDevGcTimeout{kDevGcTimeoutSec};
+// Time accounted for RPC calls.
+const std::chrono::milliseconds kRpcTime{100};
+
+template <typename R>
+std::string toString(std::chrono::duration<R, std::milli> time) {
+ return std::to_string(time.count()) + "ms";
+}
+
+/** An atomic boolean flag that indicates whether a task has finished. */
+class Flag {
+ public:
+ void onFinish() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ onFinishLocked(&lock);
+ }
+ template <typename R, typename P>
+ bool wait(std::chrono::duration<R, P> duration) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ return waitLocked(&lock, duration);
+ }
+
+ protected:
+ /** Will unlock. */
+ void onFinishLocked(std::unique_lock<std::mutex>* lock) {
+ mFinished = true;
+ lock->unlock();
+ mCv.notify_all();
+ }
+ template <typename R, typename P>
+ bool waitLocked(std::unique_lock<std::mutex>* lock, std::chrono::duration<R, P> duration) {
+ mCv.wait_for(*lock, duration, [this] { return mFinished; });
+ return mFinished;
+ }
+
+ bool mFinished{false};
+ std::mutex mMutex;
+ std::condition_variable mCv;
+};
+
+class GcCallback : public IGarbageCollectCallback, public Flag {
+ public:
+ Return<void> onFinish(Result result) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mResult = result;
+ Flag::onFinishLocked(&lock);
+ return Void();
+ }
+
+ /**
+ * Wait for a specific "timeout". If GC has finished, test that the result
+ * is equal to the "expected" value.
+ */
+ template <typename R, typename P>
+ void waitForResult(std::chrono::duration<R, P> timeout, Result expected) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (waitLocked(&lock, timeout)) {
+ EXPECT_EQ(expected, mResult);
+ } else {
+ LOG(INFO) << "timeout after " << toString(timeout);
+ }
+ }
+
+ private:
+ Result mResult{Result::UNKNOWN_ERROR};
+};
+
+/** Test environment for Health Storage HIDL HAL. */
+class HealthStorageHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ /** get the test environment singleton */
+ static HealthStorageHidlEnvironment* Instance() {
+ static HealthStorageHidlEnvironment* instance = new HealthStorageHidlEnvironment();
+ return instance;
+ }
+ virtual void registerTestServices() override { registerTestService<IStorage>(); }
+
+ private:
+ HealthStorageHidlEnvironment() {}
+};
+
+class HealthStorageHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ fs = ::testing::VtsHalHidlTargetTestBase::getService<IStorage>(
+ HealthStorageHidlEnvironment::Instance()->getServiceName<IStorage>());
+
+ ASSERT_NE(fs, nullptr);
+ LOG(INFO) << "Service is remote " << fs->isRemote();
+ }
+
+ virtual void TearDown() override {
+ EXPECT_TRUE(ping(kRpcTime))
+ << "Service is not responsive; expect subsequent tests to fail.";
+ }
+
+ /**
+ * Ping the service and expect it to return after "timeout". Return true
+ * iff the service is responsive within "timeout".
+ */
+ template <typename R, typename P>
+ bool ping(std::chrono::duration<R, P> timeout) {
+ // Ensure the service is responsive after the test.
+ sp<IStorage> service = fs;
+ auto pingFlag = std::make_shared<Flag>();
+ std::thread([service, pingFlag] {
+ service->ping();
+ pingFlag->onFinish();
+ })
+ .detach();
+ return pingFlag->wait(timeout);
+ }
+
+ sp<IStorage> fs;
+};
+
+/**
+ * Ensure garbage collection works on null callback.
+ */
+TEST_F(HealthStorageHidlTest, GcNullCallback) {
+ auto ret = fs->garbageCollect(kDevGcTimeoutSec, nullptr);
+
+ ASSERT_OK(ret);
+
+ // Hold test process because HAL can be single-threaded and doing GC.
+ ASSERT_TRUE(ping(kDevGcTimeout + kRpcTime))
+ << "Service must be available after " << toString(kDevGcTimeout + kRpcTime);
+}
+
+/**
+ * Ensure garbage collection works on non-null callback.
+ */
+TEST_F(HealthStorageHidlTest, GcNonNullCallback) {
+ sp<GcCallback> cb = new GcCallback();
+ auto ret = fs->garbageCollect(kDevGcTimeoutSec, cb);
+ ASSERT_OK(ret);
+ cb->waitForResult(kDevGcTimeout + kRpcTime, Result::SUCCESS);
+}
+
+} // namespace V1_0
+} // namespace storage
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ using ::android::hardware::configureRpcThreadpool;
+ using ::android::hardware::health::storage::V1_0::HealthStorageHidlEnvironment;
+
+ configureRpcThreadpool(1, false /* callerWillJoin*/);
+ ::testing::AddGlobalTestEnvironment(HealthStorageHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ HealthStorageHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index 85a25c6..c867ab0 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -168,7 +168,7 @@
* startup, preferably by the bootloader. This bitstring must be cryptographically bound to every
* key managed by the IKeymasterDevice. As above, the recommended mechanism for this cryptographic
* binding is to include the Root of Trust data in the input to the key derivation function used to
- * derive a key that is used to encryp the private/secret key material.
+ * derive a key that is used to encrypt the private/secret key material.
*
* The root of trust consists of a bitstring that must be derived from the public key used by
* Verified Boot to verify the signature on the boot image and from the the lock state of the
@@ -386,7 +386,7 @@
* Generates a new cryptographic key, specifying associated parameters, which must be
* cryptographically bound to the key. IKeymasterDevice implementations must disallow any use
* of a key in any way inconsistent with the authorizations specified at generation time. With
- * respect to parameters that the secure environment cannot enforce, the secure envionment's
+ * respect to parameters that the secure environment cannot enforce, the secure environment's
* obligation is limited to ensuring that the unenforceable parameters associated with the key
* cannot be modified, so that every call to getKeyCharacteristics returns the original
* values. In addition, the characteristics returned by generateKey places parameters correctly
@@ -433,7 +433,7 @@
* supported for RSA keys.
*
* o Tag::DIGEST specifies digest algorithms that may be used with the new key. TEE
- * IKeymasterDevice implementatiosn must support all Digest values (see types.hal) for RSA
+ * IKeymasterDevice implementations must support all Digest values (see types.hal) for RSA
* keys. StrongBox IKeymasterDevice implementations must support SHA_2_256.
*
* o Tag::PADDING specifies the padding modes that may be used with the new
@@ -495,13 +495,13 @@
*
* @param keyFormat The format of the key material to import. See KeyFormat in types.hal.
*
- * @pram keyData The key material to import, in the format specifed in keyFormat.
+ * @pram keyData The key material to import, in the format specified in keyFormat.
*
* @return keyBlob Opaque descriptor of the imported key. The recommended implementation
* strategy is to include an encrypted copy of the key material, wrapped in a key
* unavailable outside secure hardware.
*
- * @return keyCharacteristics Decription of the generated key. See the getKeyCharacteristics
+ * @return keyCharacteristics Description of the generated key. See the getKeyCharacteristics
* method below.
*/
importKey(vec<KeyParameter> keyParams, KeyFormat keyFormat, vec<uint8_t> keyData)
@@ -615,7 +615,7 @@
* value, it must be computationally infeasible for the secure hardware to obtain the key
* material.
*
- * @return keyCharacteristics Decription of the generated key. See KeyCharacteristics in
+ * @return keyCharacteristics Description of the generated key. See KeyCharacteristics in
* types.hal.
*/
getKeyCharacteristics(vec<uint8_t> keyBlob, vec<uint8_t> clientId, vec<uint8_t> appData)
@@ -815,7 +815,7 @@
* any one of them is higher than the corresponding current device value upgradeKey() must
* return ErrorCode::INVALID_ARGUMENT. There is one exception: it is always permissible to
* "downgrade" from any OS_VERSION number to OS_VERSION 0. For example, if the key has
- * OS_VERSION 080001, it is permisible to upgrade the key if the current system version is
+ * OS_VERSION 080001, it is permissible to upgrade the key if the current system version is
* 080100, because the new version is larger, or if the current system version is 0, because
* upgrades to 0 are always allowed. If the system version were 080000, however, keymaster must
* return ErrorCode::INVALID_ARGUMENT because that value is smaller than 080001. Values other
@@ -1040,7 +1040,7 @@
* authorizations contain Tag::CALLER_NONCE, then the caller may provide an IV/nonce with
* Tag::NONCE in inParams. If a nonce is provided when Tag::CALLER_NONCE is not authorized,
* begin() must return ErrorCode::CALLER_NONCE_PROHIBITED. If a nonce is not provided when
- * Tag::CALLER_NONCE is authorized, IKeymasterDevice msut generate a random IV/nonce.
+ * Tag::CALLER_NONCE is authorized, IKeymasterDevice must generate a random IV/nonce.
*
* -- HMAC keys --
*
@@ -1082,7 +1082,7 @@
/**
* Provides data to, and possibly receives output from, an ongoing cryptographic operation begun
- * with begin(). The operation is specified by the operationHandle paramater.
+ * with begin(). The operation is specified by the operationHandle parameter.
*
* If operationHandle is invalid, update() must return ErrorCode::INVALID_OPERATION_HANDLE.
*
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index bf77420..afbcdac 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -523,8 +523,7 @@
return *this;
}
-AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(
- std::initializer_list<V4_0::Digest> digests) {
+AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(std::vector<V4_0::Digest> digests) {
for (auto digest : digests) {
push_back(TAG_DIGEST, digest);
}
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index 6c7fd35..193e4ea 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -46,7 +46,7 @@
AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
// Move constructor.
- AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {}
+ AuthorizationSet(AuthorizationSet&& other) noexcept : data_(std::move(other.data_)) {}
// Constructor from hidl_vec<KeyParameter>
AuthorizationSet(const hidl_vec<KeyParameter>& other) { *this = other; }
@@ -58,7 +58,7 @@
}
// Move assignment.
- AuthorizationSet& operator=(AuthorizationSet&& other) {
+ AuthorizationSet& operator=(AuthorizationSet&& other) noexcept {
data_ = std::move(other.data_);
return *this;
}
@@ -278,7 +278,7 @@
AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength);
AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
- AuthorizationSetBuilder& Digest(std::initializer_list<Digest> digests);
+ AuthorizationSetBuilder& Digest(std::vector<Digest> digests);
AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings);
template <typename... T>
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 6ed61da..995ae4f 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -672,8 +672,7 @@
return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
}
-std::initializer_list<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
- std::vector<Digest> result;
+std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
switch (SecLevel()) {
case SecurityLevel::TRUSTED_ENVIRONMENT:
if (withNone) {
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 94beb21..4cd6a5b 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -214,7 +214,7 @@
std::vector<EcCurve> ValidCurves();
std::vector<EcCurve> InvalidCurves();
- std::initializer_list<Digest> ValidDigests(bool withNone, bool withMD5);
+ std::vector<Digest> ValidDigests(bool withNone, bool withMD5);
std::vector<Digest> InvalidDigests();
HidlBuf key_blob_;
diff --git a/media/bufferpool/2.0/IAccessor.hal b/media/bufferpool/2.0/IAccessor.hal
index bd70945..ab7c02d 100644
--- a/media/bufferpool/2.0/IAccessor.hal
+++ b/media/bufferpool/2.0/IAccessor.hal
@@ -68,5 +68,5 @@
generates (ResultStatus status, IConnection connection,
int64_t connectionId,
fmq_sync<BufferStatusMessage> toFmqDesc,
- fmq_sync<BufferInvalidationMessage> fromFmqDesc);
+ fmq_unsync<BufferInvalidationMessage> fromFmqDesc);
};
diff --git a/media/bufferpool/2.0/types.hal b/media/bufferpool/2.0/types.hal
index 7ce53b1..456e4aa 100644
--- a/media/bufferpool/2.0/types.hal
+++ b/media/bufferpool/2.0/types.hal
@@ -100,7 +100,7 @@
struct BufferInvalidationMessage {
/**
* Buffers from fromBufferId to toBufferId must be invalidated.
- * Both of fromBufferId and toBufferId are inclusive.
+ * fromBufferId is inclusive, but toBufferId is not inclusive.
* If fromBufferId > toBufferID, wrap happens. In that case
* the wrap is based on UINT32_MAX.
*/
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index 887fdf1..0880b2f 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -68,6 +68,7 @@
* The type of an operation in a model.
*/
enum OperationType : int32_t {
+
/**
* Adds two tensors, element-wise.
*
@@ -105,6 +106,8 @@
*
* Outputs:
* * 0: The sum, a tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 27.
*/
ADD = 0,
@@ -116,8 +119,10 @@
*
* The values in the output tensor are computed as:
*
- * output[batch, row, col, channel] =
- * sum_{i, j}(input[batch, row + i, col + j, channel]) / sum(1)
+ * output[b, i, j, channel] =
+ * sum_{di, dj}(
+ * input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+ * ) / sum(1)
*
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
@@ -171,7 +176,9 @@
*
* Outputs:
* * 0: The output 4-D tensor, of shape
- [batches, out_height, out_width, depth].
+ * [batches, out_height, out_width, depth].
+ *
+ * Available since API level 27.
*/
AVERAGE_POOL_2D = 1,
@@ -198,6 +205,8 @@
* 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].
+ *
+ * Available since API level 27.
*/
CONCATENATION = 2,
@@ -213,12 +222,11 @@
*
* The values in the output tensor are computed as:
*
- * output[batch, row, col, channel] =
- * sum_{i, j} (
- * input[batch, row + i, col + j, k] *
- * filter[channel, row + i, col + j, k] +
- * bias[channel]
- * )
+ * output[b, i, j, channel] =
+ * sum_{di, dj, k} (
+ * input[b, strides[1] * i + di, strides[2] * j + dj, k] *
+ * filter[channel, di, dj, k]
+ * ) + bias[channel]
*
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
@@ -274,7 +282,7 @@
* * 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.
+ * 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.
@@ -284,6 +292,8 @@
* [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.
+ *
+ * Available since API level 27.
*/
CONV_2D = 3,
@@ -307,7 +317,7 @@
* sum_{di, dj} (
* input[b, strides[1] * i + di, strides[2] * j + dj, k] *
* filter[1, di, dj, k * channel_multiplier + q]
- * )
+ * ) + bias[k * channel_multiplier + q]
*
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
@@ -375,6 +385,8 @@
* [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.
+ *
+ * Available since API level 27.
*/
DEPTHWISE_CONV_2D = 4,
@@ -409,6 +421,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape [batch, height*block_size,
* width*block_size, depth/(block_size*block_size)].
+ *
+ * Available since API level 27.
*/
DEPTH_TO_SPACE = 5,
@@ -430,6 +444,8 @@
* Outputs:
* * 0: The output tensor of same shape as input0, but with
* {@link OperandType::TENSOR_FLOAT32}.
+ *
+ * Available since API level 27.
*/
DEQUANTIZE = 6,
@@ -463,6 +479,8 @@
* * 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.
+ *
+ * Available since API level 27.
*/
EMBEDDING_LOOKUP = 7,
@@ -480,6 +498,8 @@
* Outputs:
* * 0: The output tensor, of the same {@link OperandType} and dimensions as
* the input tensor.
+ *
+ * Available since API level 27.
*/
FLOOR = 8,
@@ -523,6 +543,8 @@
* tensor of {@link OperandType::TENSOR_QUANT8_ASYMM}, the following
* condition must be satisfied:
* output_scale > input_scale * filter_scale.
+ *
+ * Available since API level 27.
*/
FULLY_CONNECTED = 9,
@@ -571,6 +593,8 @@
* 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.
+ *
+ * Available since API level 27.
*/
HASHTABLE_LOOKUP = 10,
@@ -598,6 +622,8 @@
* Outputs:
* * 0: The output 4-D tensor, of the same shape as input
* [batches, height, width, depth].
+ *
+ * Available since API level 27.
*/
L2_NORMALIZATION = 11,
@@ -609,8 +635,8 @@
*
* The values in the output tensor are computed as:
*
- * output[batch, row, col, channel] =
- * sqrt(sum_{i, j} pow(input[batch, row + i, col + j, channel], 2) /
+ * output[b, i, j, c] =
+ * sqrt(sum_{di, dj} pow(input[b, strides[1] * i + di, strides[2] * j + dj, c], 2) /
* sum(1))
*
* Supported tensor {@link OperandType}:
@@ -664,6 +690,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, out_height, out_width, depth].
+ *
+ * Available since API level 27.
*/
L2_POOL_2D = 12,
@@ -700,6 +728,8 @@
*
* Outputs:
* * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 27.
*/
LOCAL_RESPONSE_NORMALIZATION = 13,
@@ -723,6 +753,8 @@
* * 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.
+ *
+ * Available since API level 27.
*/
LOGISTIC = 14,
@@ -758,6 +790,8 @@
* If the projection type is Dense:
* Output.Dim == { Tensor[0].Dim[0] * Tensor[0].Dim[1] }
* A flattened tensor that represents projected bit vectors.
+ *
+ * Available since API level 27.
*/
LSH_PROJECTION = 15,
@@ -952,6 +986,8 @@
* 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.
+ *
+ * Available since API level 27.
*/
LSTM = 16,
@@ -963,8 +999,10 @@
*
* The values in the output tensor are computed as:
*
- * output[batch, row, col, channel] =
- * max_{i, j} (input[batch, row + i, col + j, channel])
+ * output[b, i, j, channel] =
+ * max_{di, dj} (
+ * input[b, strides[1] * i + di, strides[2] * j + dj, channel]
+ * )
*
* Supported tensor {@link OperandType}:
* * {@link OperandType::TENSOR_FLOAT32}
@@ -1018,6 +1056,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, out_height, out_width, depth].
+ *
+ * Available since API level 27.
*/
MAX_POOL_2D = 17,
@@ -1055,6 +1095,8 @@
* For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
* the following condition must be satisfied:
* output_scale > input1_scale * input2_scale.
+ *
+ * Available since API level 27.
*/
MUL = 18,
@@ -1076,6 +1118,8 @@
*
* Outputs:
* * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 27.
*/
RELU = 19,
@@ -1097,6 +1141,8 @@
*
* Outputs:
* * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 27.
*/
RELU1 = 20,
@@ -1118,6 +1164,8 @@
*
* Outputs:
* * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 27.
*/
RELU6 = 21,
@@ -1141,6 +1189,8 @@
*
* Outputs:
* * 0: The output tensor, of shape specified by the input shape.
+ *
+ * Available since API level 27.
*/
RESHAPE = 22,
@@ -1167,6 +1217,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape
* [batches, new_height, new_width, depth].
+ *
+ * Available since API level 27.
*/
RESIZE_BILINEAR = 23,
@@ -1222,6 +1274,8 @@
* 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.
+ *
+ * Available since API level 27.
*/
RNN = 24,
@@ -1251,6 +1305,8 @@
* * 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.
+ *
+ * Available since API level 27.
*/
SOFTMAX = 25,
@@ -1284,6 +1340,8 @@
* Outputs:
* * 0: The output 4-D tensor, of shape [batches, height/block_size,
* width/block_size, depth_in*block_size*block_size].
+ *
+ * Available since API level 27.
*/
SPACE_TO_DEPTH = 26,
@@ -1361,7 +1419,9 @@
* [batch_size, (memory_size - 1) * num_units * rank].
* * 1: output.
* A 2-D tensor of {@link OperandType::TENSOR_FLOAT32}, of shape
- * [batch_size, num_units].
+ * [batch_size, num_units].
+ *
+ * Available since API level 27.
*/
SVDF = 27,
@@ -1382,6 +1442,8 @@
*
* Outputs:
* * 0: The output tensor of same shape as input0.
+ *
+ * Available since API level 27.
*/
TANH = 28,
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index e28113b..18f35c1 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -25,6 +25,7 @@
static_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
@@ -49,8 +50,9 @@
],
defaults: ["VtsHalTargetTestDefaults"],
static_libs: [
- "android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 64495cf..b8046c7 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -275,6 +275,58 @@
EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
}
+// TODO: Reduce code duplication.
+void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
+ std::function<bool(int)> is_ignored,
+ const std::vector<MixedTypedExampleType>& examples) {
+ V1_2::Model model = create_model();
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ Return<void> supportedCall = device->getSupportedOperations_1_2(
+ 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(supportedCall.isOk());
+
+ // launch prepare model
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
+ 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();
+ sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
+
+ // early termination if vendor service cannot fully prepare model
+ 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;
+ }
+ EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
+ ASSERT_NE(nullptr, preparedModel.get());
+
+ // TODO: Adjust the error limit based on testing.
+ // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
+ float fpAtol = !model.relaxComputationFloat32toFloat16 ? 1e-5f : 5.0f * 0.0009765625f;
+ // Set the relative tolerance to be 5ULP of the corresponding FP precision.
+ float fpRtol = !model.relaxComputationFloat32toFloat16 ? 5.0f * 1.1920928955078125e-7f
+ : 5.0f * 0.0009765625f;
+ EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
+}
+
} // namespace generated_tests
} // namespace neuralnetworks
diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal
index 7b2a21a..c9de76b 100644
--- a/neuralnetworks/1.1/types.hal
+++ b/neuralnetworks/1.1/types.hal
@@ -26,6 +26,7 @@
* The type of an operation in a model.
*/
enum OperationType : @1.0::OperationType {
+
/**
* BatchToSpace for N-dimensional tensors.
*
@@ -50,6 +51,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 28.
*/
BATCH_TO_SPACE_ND = 29,
@@ -88,6 +91,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 28.
*/
DIV = 30,
@@ -118,6 +123,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 28.
*/
MEAN = 31,
@@ -150,6 +157,8 @@
* of the padding:
* output0.dimension[i] =
* padding[i, 0] + input0.dimension[i] + padding[i, 1]
+ *
+ * Available since API level 28.
*/
PAD = 32,
@@ -185,6 +194,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 28.
*/
SPACE_TO_BATCH_ND = 33,
@@ -214,6 +225,8 @@
* * 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.
+ *
+ * Available since API level 28.
*/
SQUEEZE = 34,
@@ -234,28 +247,32 @@
*
* Inputs:
* * 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
+ * * 1: begin, 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: end, 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: strides, 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). The entries must be non-zero.
+ * * 4: begin_mask, an {@link OperandType::INT32} scalar. 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
+ * * 5: end_mask, an {@link OperandType::INT32} scalar. 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.
+ * * 6: shrink_axis_mask, an {@link OperandType::INT32} scalar. If the
+ * ith bit of shrink_axis_mask is set, the ith dimension specification
+ * shrinks the dimensionality by 1, taking on the value at index
+ * begin[i]. In this case, the ith specification must define a
+ * slice of size 1, e.g. begin[i] = x, end[i] = x + 1.
*
* Outputs:
- * * 0: A tensor of the same {@link OperandType} as input0.
+ * * 0: A tensor of the same {@link OperandType} as input0 and rank (n - k),
+ * where k is the number of bits set in shrink_axis_mask.
+ *
+ * Available since API level 28.
*/
STRIDED_SLICE = 35,
@@ -294,6 +311,8 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 28.
*/
SUB = 36,
@@ -319,8 +338,11 @@
*
* Outputs:
* * 0: A tensor of the same {@link OperandType} as input0.
+ *
+ * Available since API level 28.
*/
TRANSPOSE = 37,
+
};
/**
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index f755c20..52a804a 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -28,6 +28,7 @@
static_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libhidlmemory",
diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp
new file mode 100644
index 0000000..e183a26
--- /dev/null
+++ b/neuralnetworks/1.2/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.neuralnetworks@1.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IDevice.hal",
+ ],
+ interfaces: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "Model",
+ "Operation",
+ "OperationType",
+ ],
+ gen_java: false,
+}
diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal
new file mode 100644
index 0000000..9cc23a2
--- /dev/null
+++ b/neuralnetworks/1.2/IDevice.hal
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+package android.hardware.neuralnetworks@1.2;
+
+import @1.0::ErrorStatus;
+import @1.0::IPreparedModelCallback;
+import @1.1::ExecutionPreference;
+import @1.1::IDevice;
+
+/**
+ * This interface represents a device driver.
+ */
+interface IDevice extends @1.1::IDevice {
+ /**
+ * Gets the supported operations in a model.
+ *
+ * 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.
+ *
+ * @param model A model whose operations--and their corresponding operands--
+ * are to be verified by the driver.
+ * @return status Error status of the call, must be:
+ * - NONE if successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if provided model is invalid
+ * @return supportedOperations A list of supported operations, where true
+ * indicates the operation is supported and false indicates the
+ * operation is not supported. The index of "supported" corresponds with
+ * the index of the operation it is describing.
+ */
+ getSupportedOperations_1_2(Model model)
+ generates (ErrorStatus status, vec<bool> supportedOperations);
+
+ /**
+ * Creates a prepared model for execution.
+ *
+ * prepareModel is used to make any necessary transformations or alternative
+ * representations to a model for execution, possibly including
+ * transformations on the constant data, optimization on the model's graph,
+ * or compilation into the device's native binary format. The model itself
+ * is not changed.
+ *
+ * The model is prepared asynchronously with respect to the caller. The
+ * prepareModel function must verify the inputs to the prepareModel function
+ * are correct. If there is an error, prepareModel must immediately invoke
+ * the callback with the appropriate ErrorStatus value and nullptr for the
+ * IPreparedModel, then return with the same ErrorStatus. If the inputs to
+ * the prepareModel function are valid and there is no error, prepareModel
+ * must launch an asynchronous task to prepare the model in the background,
+ * and immediately return from prepareModel with ErrorStatus::NONE. If the
+ * asynchronous task fails to launch, prepareModel must immediately invoke
+ * the callback with ErrorStatus::GENERAL_FAILURE and nullptr for the
+ * IPreparedModel, then return with ErrorStatus::GENERAL_FAILURE.
+ *
+ * When the asynchronous task has finished preparing the model, it must
+ * immediately invoke the callback function provided as an input to
+ * prepareModel. If the model was prepared successfully, the callback object
+ * must be invoked with an error status of ErrorStatus::NONE and the
+ * produced IPreparedModel object. If an error occurred preparing the model,
+ * the callback object must be invoked with the appropriate ErrorStatus
+ * value and nullptr for the IPreparedModel.
+ *
+ * The only information that may be unknown to the model at this stage is
+ * the shape of the tensors, which may only be known at execution time. As
+ * such, some driver services may return partially prepared models, where
+ * the prepared model may only be finished when it is paired with a set of
+ * inputs to the model. Note that the same prepared model object may be
+ * used with different shapes of inputs on different (possibly concurrent)
+ * executions.
+ *
+ * Multiple threads may call prepareModel on the same model concurrently.
+ *
+ * @param model The model to be prepared for execution.
+ * @param preference Indicates the intended execution behavior of a prepared
+ * model.
+ * @param callback A callback object used to return the error status of
+ * preparing the model for execution and the prepared model if
+ * successful, nullptr otherwise. The callback object's notify function
+ * must be called exactly once, even if the model could not be prepared.
+ * @return status Error status of launching a task which prepares the model
+ * in the background; must be:
+ * - NONE if preparation task is successfully launched
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid
+ */
+ prepareModel_1_2(Model model, ExecutionPreference preference,
+ IPreparedModelCallback callback)
+ generates (ErrorStatus status);
+};
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
new file mode 100644
index 0000000..4377131
--- /dev/null
+++ b/neuralnetworks/1.2/types.hal
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+package android.hardware.neuralnetworks@1.2;
+
+import @1.0::Operand;
+import @1.0::PerformanceInfo;
+import @1.1::OperationType;
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : @1.1::OperationType {
+ // TODO(b/116445845): Sync docs when all ops are implemented.
+ ARGMAX = 38,
+ ARGMIN = 39,
+ PAD_V2 = 40,
+ BBOX_TRANSFORM = 41,
+ BIDIRECTIONAL_SEQUENCE_LSTM = 42,
+ BIDIRECTIONAL_SEQUENCE_RNN = 43,
+ BOX_WITH_NMS_LIMIT = 44,
+ CAST = 45,
+ CHANNEL_SHUFFLE = 46,
+ DETECTION_OUTPUT = 47,
+ EMBEDDING_LOOKUP_SPARSE = 48,
+ EXP = 49,
+ EXPAND_DIMS = 50,
+ GATHER = 51,
+ GENERATE_PROPOSALS = 52,
+ GREATER = 53,
+ GREATER_EQUAL = 54,
+ GROUPED_CONV_2D = 55,
+ HEATMAP_MAX_KEYPOINT = 56,
+ LESS = 57,
+ LESS_EQUAL = 58,
+ LOG = 59,
+ LOGICAL_AND = 60,
+ LOGICAL_NOT = 61,
+ LOGICAL_OR = 62,
+ LOG_SOFTMAX = 63,
+ MAXIMUM = 64,
+ MINIMUM = 65,
+ NEG = 66,
+ POW = 67,
+ PRELU = 68,
+ PRIOR_BOX = 69,
+ QUANTIZE = 70,
+ QUANTIZED_16BIT_LSTM = 71,
+ RANDOM_MULTINOMIAL = 72,
+ REDUCE = 73,
+ ROI_ALIGN = 74,
+ RSQRT = 75,
+ SELECT = 76,
+ SIN = 77,
+ SLICE = 78,
+ SPARSE_TO_DENSE = 79,
+ SPLIT = 80,
+ SQRT = 81,
+ TILE = 82,
+ TOPK_V2 = 83,
+ TRANSPOSE_CONV_2D = 84,
+ UNIDIRECTIONAL_SEQUENCE_LSTM = 85,
+ UNIDIRECTIONAL_SEQUENCE_RNN = 86,
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+ /**
+ * The operation type.
+ */
+ OperationType type;
+
+ /**
+ * Describes the table that contains the indexes of the inputs of the
+ * operation. The offset is the index in the operandIndexes table.
+ */
+ vec<uint32_t> inputs;
+
+ /**
+ * Describes the table that contains the indexes of the outputs of the
+ * operation. The offset is the index in the operandIndexes table.
+ */
+ vec<uint32_t> outputs;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+ /**
+ * All operands included in the model.
+ */
+ vec<Operand> operands;
+
+ /**
+ * All operations included in the model.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
+ */
+ vec<Operation> operations;
+
+ /**
+ * Input indexes of the model. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the model. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
+
+ /**
+ * A byte buffer containing operand data that were copied into the model.
+ *
+ * An operand's value must be located here if and only if Operand::lifetime
+ * equals OperandLifeTime::CONSTANT_COPY.
+ */
+ vec<uint8_t> operandValues;
+
+ /**
+ * A collection of shared memory pools containing operand values.
+ *
+ * An operand's value must be located here if and only if Operand::lifetime
+ * equals OperandLifeTime::CONSTANT_REFERENCE.
+ */
+ vec<memory> pools;
+
+ /**
+ * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+ * precision as low as that of the IEEE 754 16-bit floating-point format.
+ * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+ * range and precision of the IEEE 754 32-bit floating-point format.
+ */
+ bool relaxComputationFloat32toFloat16;
+};
diff --git a/neuralnetworks/1.2/vts/OWNERS b/neuralnetworks/1.2/vts/OWNERS
new file mode 100644
index 0000000..8f25436
--- /dev/null
+++ b/neuralnetworks/1.2/vts/OWNERS
@@ -0,0 +1,14 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+mikie@google.com
+mks@google.com
+pszczepaniak@google.com
+slavash@google.com
+
+# VTS team
+yim@google.com
+yuexima@google.com
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..2dc19cc
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -0,0 +1,52 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalNeuralnetworksV1_2TargetTest",
+ srcs: [
+ "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.2",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libneuralnetworks_utils",
+ "VtsHalNeuralnetworksTest_utils",
+ ],
+ header_libs: [
+ "libneuralnetworks_headers",
+ "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.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
new file mode 100644
index 0000000..d2dea1d
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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_2 {
+namespace vts {
+namespace functional {
+
+using V1_1::Capabilities;
+
+// 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));
+}
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
new file mode 100644
index 0000000..662c531
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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_2::IDevice>&, std::function<V1_2::Model(void)>,
+ std::function<bool(int)>, const std::vector<MixedTypedExampleType>&);
+} // namespace generated_tests
+
+namespace V1_2 {
+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"
+#include "all_generated_V1_2_vts_tests.cpp"
+
+} // namespace functional
+} // namespace vts
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/Models.h b/neuralnetworks/1.2/vts/functional/Models.h
new file mode 100644
index 0000000..f3769bc
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/Models.h
@@ -0,0 +1,378 @@
+/*
+ * 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_2_VTS_FUNCTIONAL_MODELS_H
+#define VTS_HAL_NEURALNETWORKS_V1_2_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>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_2 {
+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_float_5_relaxed) \
+ 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_float_1_relaxed) \
+ FN(batch_to_space_quant8_1) \
+ FN(batch_to_space_relaxed) \
+ 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_2_relaxed) \
+ 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_2_relaxed) \
+ FN(depthwise_conv2d_float_large) \
+ FN(depthwise_conv2d_float_large_2) \
+ FN(depthwise_conv2d_float_large_2_relaxed) \
+ FN(depthwise_conv2d_float_large_2_weights_as_inputs) \
+ FN(depthwise_conv2d_float_large_2_weights_as_inputs_relaxed) \
+ 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_relaxed) \
+ FN(depthwise_conv2d_float_weights_as_inputs) \
+ FN(depthwise_conv2d_float_weights_as_inputs_relaxed) \
+ 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(dequantize_relaxed) \
+ FN(div) \
+ FN(div_broadcast_float) \
+ FN(div_broadcast_float_relaxed) \
+ FN(div_relaxed) \
+ 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_2_relaxed) \
+ FN(fully_connected_float_4d_simple) \
+ FN(fully_connected_float_4d_simple_relaxed) \
+ FN(fully_connected_float_large) \
+ FN(fully_connected_float_large_relaxed) \
+ FN(fully_connected_float_large_weights_as_inputs) \
+ FN(fully_connected_float_large_weights_as_inputs_relaxed) \
+ 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_2_relaxed) \
+ 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_2_relaxed) \
+ FN(l2_pool_float_large) \
+ FN(l2_pool_float_large_relaxed) \
+ 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_float_4_relaxed) \
+ 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_1_relaxed) \
+ FN(mean_float_2) \
+ FN(mean_float_2_relaxed) \
+ FN(mean_quant8_1) \
+ FN(mean_quant8_2) \
+ FN(mean_relaxed) \
+ 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(pad_float_1_relaxed) \
+ FN(pad_relaxed) \
+ 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_float_2_relaxed) \
+ 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_2_relaxed) \
+ 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_1_relaxed) \
+ FN(space_to_batch_float_2) \
+ FN(space_to_batch_float_2_relaxed) \
+ FN(space_to_batch_float_3) \
+ FN(space_to_batch_float_3_relaxed) \
+ FN(space_to_batch_quant8_1) \
+ FN(space_to_batch_quant8_2) \
+ FN(space_to_batch_quant8_3) \
+ FN(space_to_batch_relaxed) \
+ 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_float_1_relaxed) \
+ FN(squeeze_quant8_1) \
+ FN(squeeze_relaxed) \
+ FN(strided_slice) \
+ FN(strided_slice_float_1) \
+ FN(strided_slice_float_10) \
+ FN(strided_slice_float_10_relaxed) \
+ FN(strided_slice_float_11) \
+ FN(strided_slice_float_11_relaxed) \
+ FN(strided_slice_float_1_relaxed) \
+ FN(strided_slice_float_2) \
+ FN(strided_slice_float_2_relaxed) \
+ FN(strided_slice_float_3) \
+ FN(strided_slice_float_3_relaxed) \
+ FN(strided_slice_float_4) \
+ FN(strided_slice_float_4_relaxed) \
+ FN(strided_slice_float_5) \
+ FN(strided_slice_float_5_relaxed) \
+ FN(strided_slice_float_6) \
+ FN(strided_slice_float_6_relaxed) \
+ FN(strided_slice_float_7) \
+ FN(strided_slice_float_7_relaxed) \
+ FN(strided_slice_float_8) \
+ FN(strided_slice_float_8_relaxed) \
+ FN(strided_slice_float_9) \
+ FN(strided_slice_float_9_relaxed) \
+ FN(strided_slice_qaunt8_10) \
+ FN(strided_slice_qaunt8_11) \
+ 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(strided_slice_relaxed) \
+ FN(sub) \
+ FN(sub_broadcast_float) \
+ FN(sub_broadcast_float_relaxed) \
+ FN(sub_relaxed) \
+ 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_float_1_relaxed) \
+ FN(transpose_quant8_1) \
+ FN(transpose_relaxed)
+
+#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_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+#endif // VTS_HAL_NEURALNETWORKS_V1_2_VTS_FUNCTIONAL_MODELS_H
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
new file mode 100644
index 0000000..7ec6ff1
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -0,0 +1,538 @@
+/*
+ * 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_2 {
+
+using V1_0::IPreparedModel;
+using V1_0::Operand;
+using V1_0::OperandLifeTime;
+using V1_0::OperandType;
+using V1_1::ExecutionPreference;
+
+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 Model& model) {
+ SCOPED_TRACE(message + " [getSupportedOperations_1_2]");
+
+ Return<void> ret =
+ device->getSupportedOperations_1_2(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 Model& model, ExecutionPreference preference) {
+ SCOPED_TRACE(message + " [prepareModel_1_2]");
+
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+ ASSERT_NE(nullptr, preparedModelCallback.get());
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_2(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, 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 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 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 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 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 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 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 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 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 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 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 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 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 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 == 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 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 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 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 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 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_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
new file mode 100644
index 0000000..f4476fa
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -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_2 {
+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::for_all;
+using test_helper::MixedTyped;
+using test_helper::MixedTypedExampleType;
+
+///////////////////////// UTILITY FUNCTIONS /////////////////////////
+
+static void createPreparedModel(const sp<IDevice>& device, const Model& model,
+ sp<IPreparedModel>* preparedModel) {
+ ASSERT_NE(nullptr, preparedModel);
+
+ // see if service can handle model
+ bool fullySupportsModel = false;
+ Return<void> supportedOpsLaunchStatus = device->getSupportedOperations_1_2(
+ 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_2(
+ 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_2 call returns a list of operations that are
+ // guaranteed not to fail if prepareModel_1_2 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 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_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/ValidationTests.cpp b/neuralnetworks/1.2/vts/functional/ValidationTests.cpp
new file mode 100644
index 0000000..3bdc5cd
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/ValidationTests.cpp
@@ -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_2 {
+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_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
new file mode 100644
index 0000000..90a910c
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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_2 {
+namespace vts {
+namespace functional {
+
+// A class for test environment setup
+NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {}
+
+NeuralnetworksHidlEnvironment::~NeuralnetworksHidlEnvironment() {}
+
+NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
+ // This has to return a "new" object because it is freed inside
+ // ::testing::AddGlobalTestEnvironment when the gtest is being torn down
+ static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
+ return instance;
+}
+
+void NeuralnetworksHidlEnvironment::registerTestServices() {
+ registerTestService<IDevice>();
+}
+
+// The main test class for NEURALNETWORK HIDL HAL.
+NeuralnetworksHidlTest::NeuralnetworksHidlTest() {}
+
+NeuralnetworksHidlTest::~NeuralnetworksHidlTest() {}
+
+void NeuralnetworksHidlTest::SetUp() {
+ ::testing::VtsHalHidlTargetTestBase::SetUp();
+ device = ::testing::VtsHalHidlTargetTestBase::getService<IDevice>(
+ NeuralnetworksHidlEnvironment::getInstance());
+ ASSERT_NE(nullptr, device.get());
+}
+
+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_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+using android::hardware::neuralnetworks::V1_2::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.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
new file mode 100644
index 0000000..a87d788
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -0,0 +1,92 @@
+/*
+ * 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_2_H
+#define VTS_HAL_NEURALNETWORKS_V1_2_H
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+#include <android-base/macros.h>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_2 {
+
+using V1_0::DeviceStatus;
+using V1_0::ErrorStatus;
+using V1_0::Request;
+
+namespace vts {
+namespace functional {
+
+// A class for test environment setup
+class NeuralnetworksHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
+ NeuralnetworksHidlEnvironment();
+ ~NeuralnetworksHidlEnvironment() override;
+
+ public:
+ 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;
+
+ 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
+::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
+::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
+
+} // namespace V1_2
+} // namespace neuralnetworks
+} // namespace hardware
+} // namespace android
+
+#endif // VTS_HAL_NEURALNETWORKS_V1_2_H
diff --git a/radio/1.3/Android.bp b/radio/1.3/Android.bp
index 042df6c..5ac38cd 100644
--- a/radio/1.3/Android.bp
+++ b/radio/1.3/Android.bp
@@ -20,8 +20,10 @@
],
types: [
"AccessNetwork",
+ "DataRegStateResult",
"EmergencyNumber",
"EmergencyServiceCategory",
+ "LteVopsInfo",
],
gen_java: true,
}
diff --git a/radio/1.3/IRadioResponse.hal b/radio/1.3/IRadioResponse.hal
index 6912d0a..3604953 100644
--- a/radio/1.3/IRadioResponse.hal
+++ b/radio/1.3/IRadioResponse.hal
@@ -71,4 +71,18 @@
* RadioError:CANCELLED
*/
oneway emergencyDialResponse(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
+ * types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NOT_PROVISIONED
+ */
+ oneway getDataRegistrationStateResponse_1_3(RadioResponseInfo info,
+ DataRegStateResult dataRegResponse);
};
diff --git a/radio/1.3/types.hal b/radio/1.3/types.hal
index c04451f..d472ca7 100644
--- a/radio/1.3/types.hal
+++ b/radio/1.3/types.hal
@@ -16,7 +16,10 @@
package android.hardware.radio@1.3;
+import @1.0::RegState;
import @1.2::AccessNetwork;
+import @1.2::CellIdentity;
+import @1.2::DataRegStateResult;
enum AccessNetwork : @1.2::AccessNetwork {
/**
@@ -81,3 +84,39 @@
MIEC = 1 << 5, // Manually Initiated eCall (MIeC)
AIEC = 1 << 6, // Automatically Initiated eCall (AIeC)
};
+
+/**
+ * Type to define the LTE specific network capabilities for voice over PS including
+ * emergency and normal voice calls.
+ */
+struct LteVopsInfo {
+ /**
+ * This indicates if camped network support VoLTE services. This information is received
+ * from LTE network during LTE NAS registration procedure through LTE ATTACH ACCEPT/TAU
+ * ACCEPT. Refer 3GPP 24.301 EPS network feature support -> IMS VoPS
+ */
+ bool isVopsSupported;
+ /**
+ * This indicates if camped network support VoLTE emergency bearers. This information
+ * is received from LTE network through two sources:
+ * a. During LTE NAS registration procedure through LTE ATTACH ACCEPT/TAU ACCEPT. Refer
+ * 3GPP 24.301 EPS network feature support -> EMC BS
+ * b. In case device is not registered on network. Refer 3GPP 25.331 LTE RRC
+ * SIB1 : ims-EmergencySupport-r9
+ * If device is registered on LTE, then this field indicates (a).
+ * In case of limited service on LTE this field indicates (b).
+ */
+ bool isEmcBearerSupported;
+};
+
+struct DataRegStateResult {
+ @1.2::DataRegStateResult base;
+ /**
+ * Network capabilities for voice over PS services. This info is valid only
+ * on LTE network and must be present when device is camped on LTE. vopsInfo
+ * will be empty when device is camped only on 2G/3G .
+ */
+ safe_union VopsInfo {
+ LteVopsInfo lteVopsInfo; // LTE network capability
+ } vopsInfo;
+};
diff --git a/sensors/2.0/Android.bp b/sensors/2.0/Android.bp
new file mode 100644
index 0000000..3b948a9
--- /dev/null
+++ b/sensors/2.0/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.sensors@2.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ISensors.hal",
+ "ISensorsCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.sensors@1.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "EventQueueFlagBits",
+ "SensorTimeout",
+ ],
+ gen_java: false,
+}
+
diff --git a/sensors/2.0/ISensors.hal b/sensors/2.0/ISensors.hal
new file mode 100644
index 0000000..2a57251
--- /dev/null
+++ b/sensors/2.0/ISensors.hal
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors@2.0;
+
+import @1.0::Event;
+import @1.0::OperationMode;
+import @1.0::RateLevel;
+import @1.0::Result;
+import @1.0::SensorInfo;
+import @1.0::SharedMemInfo;
+import @2.0::ISensorsCallback;
+
+interface ISensors {
+ /**
+ * Enumerate all available (static) sensors.
+ */
+ getSensorsList() generates (vec<SensorInfo> list);
+
+ /**
+ * Place the module in a specific mode. The following modes are defined
+ *
+ * SENSOR_HAL_NORMAL_MODE - Normal operation. Default state of the module.
+ *
+ * SENSOR_HAL_DATA_INJECTION_MODE - Loopback mode.
+ * Data is injected for the supported sensors by the sensor service in
+ * this mode.
+ *
+ * @return OK on success
+ * BAD_VALUE if requested mode is not supported
+ * PERMISSION_DENIED if operation is not allowed
+ */
+ setOperationMode(OperationMode mode) generates (Result result);
+
+ /**
+ * Activate/de-activate one sensor.
+ *
+ * After sensor de-activation, existing sensor events that have not
+ * been written to the event queue must be abandoned immediately so that
+ * subsequent activations do not get stale sensor events (events
+ * that are generated prior to the latter activation).
+ *
+ * @param sensorHandle is the handle of the sensor to change.
+ * @param enabled set to true to enable, or false to disable the sensor.
+ * @return result OK on success, BAD_VALUE if sensorHandle is invalid.
+ */
+ activate(int32_t sensorHandle, bool enabled) generates (Result result);
+
+ /**
+ * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback.
+ *
+ * The Fast Message Queues (FMQ) that are used to send data between the
+ * framework and the HAL. The callback is used by the HAL to notify the
+ * framework of asynchronous events, such as a dynamic sensor connection.
+ *
+ * The Event FMQ is used to transport sensor events from the HAL to the
+ * framework. The Event FMQ is created using the eventQueueDescriptor.
+ * Data may only be written to the Event FMQ. Data must not be read from
+ * the Event FMQ since the framework is the only reader. Upon receiving
+ * sensor events, the HAL should write the sensor events to the Event FMQ.
+ * Once the HAL is finished writing sensor events to the Event FMQ, the HAL
+ * must call the Event FMQ's EventFlag wake() function with the
+ * EventQueueFlagBits::READ_AND_PROCESS mask which notifies the framework
+ * that sensor events are available to be read and processed.
+ *
+ * The Wake Lock FMQ is used by the framework to notify the HAL when it is
+ * safe to release its wake_lock. When the framework receives WAKE_UP events
+ * from the Event FMQ and the framework has acquired a wake_lock, the
+ * framework must write a WakeLockEvent to the Wake Lock FMQ with the number
+ * of WAKE_UP events processed. When the HAL reads the WakeLockEvent from
+ * the Wake Lock FMQ, the HAL should decrement its current count of
+ * unprocessed WAKE_UP events and release its wake_lock if the current
+ * count of unprocessed WAKE_UP events is zero.
+ *
+ * The ISensorsCallback is used by the HAL to notify the framework of
+ * asynchronous events, such as a dynamic sensor connection.
+ *
+ * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events
+ * must begin with "SensorsHAL_WAKEUP".
+ *
+ * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP
+ * event was written to the Event FMQ without receiving a message on the
+ * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be
+ * released.
+ *
+ * If either the Event FMQ or the Wake Lock FMQ is already initialized when
+ * initialize is invoked, then both existing FMQs must be discarded and the
+ * new descriptors must be used to create new FMQs within the HAL. The
+ * number of outstanding WAKE_UP events should also be reset to zero, and
+ * any outstanding wake_locks held as a result of WAKE_UP events should be
+ * released.
+ *
+ * initialize must be thread safe and prevent concurrent calls
+ * to initialize from simultaneously modifying state.
+ *
+ * @param eventQueueDescriptor Fast Message Queue descriptor that is used to
+ * create the Event FMQ which is where sensor events are written. The
+ * descriptor is obtained from the framework's FMQ that is used to read
+ * sensor events.
+ * @param wakeLockDescriptor Fast Message Queue descriptor that is used to
+ * create the Wake Lock FMQ which is where wake_lock events are read
+ * from. The descriptor is obtained from the framework's FMQ that is
+ * used to write wake_lock events.
+ * @param sensorsCallback sensors callback that receives asynchronous data
+ * from the Sensors HAL.
+ * @return result OK on success; BAD_VALUE if descriptor is invalid (such
+ * as null)
+ */
+ @entry
+ @callflow(next = {"getSensorsList"})
+ initialize(fmq_sync<Event> eventQueueDescriptor,
+ fmq_sync<uint32_t> wakeLockDescriptor,
+ ISensorsCallback sensorsCallback)
+ generates
+ (Result result);
+
+ /**
+ * Sets a sensor’s parameters, including sampling frequency and maximum
+ * report latency. This function can be called while the sensor is
+ * activated, in which case it must not cause any sensor measurements to
+ * be lost: transitioning from one sampling rate to the other cannot cause
+ * lost events, nor can transitioning from a high maximum report latency to
+ * a low maximum report latency.
+ *
+ * @param sensorHandle handle of sensor to be changed.
+ * @param samplingPeriodNs specifies sensor sample period in nanoseconds.
+ * @param maxReportLatencyNs allowed delay time before an event is sampled
+ * to time of report.
+ * @return result OK on success, BAD_VALUE if any parameters are invalid.
+ */
+ batch(int32_t sensorHandle,
+ int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs)
+ generates (
+ Result result);
+
+ /**
+ * Trigger a flush of internal FIFO.
+ *
+ * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode"
+ * FIFO for the specified sensor and flushes the FIFO. If the FIFO is empty
+ * or if the sensor doesn't support batching (FIFO size zero), return
+ * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream.
+ * This applies to all sensors other than one-shot sensors. If the sensor
+ * is a one-shot sensor, flush must return BAD_VALUE and not generate any
+ * flush complete metadata. If the sensor is not active at the time flush()
+ * is called, flush() return BAD_VALUE.
+ *
+ * @param sensorHandle handle of sensor to be flushed.
+ * @return result OK on success and BAD_VALUE if sensorHandle is invalid.
+ */
+ flush(int32_t sensorHandle) generates (Result result);
+
+ /**
+ * Inject a single sensor event or push operation environment parameters to
+ * device.
+ *
+ * When device is in NORMAL mode, this function is called to push operation
+ * environment data to device. In this operation, Event is always of
+ * SensorType::AdditionalInfo type. See operation evironment parameters
+ * section in AdditionalInfoType.
+ *
+ * When device is in DATA_INJECTION mode, this function is also used for
+ * injecting sensor events.
+ *
+ * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+ * type events should not be routed back to the sensor event queue.
+ *
+ * @see AdditionalInfoType
+ * @see OperationMode
+ * @param event sensor event to be injected
+ * @return result OK on success; PERMISSION_DENIED if operation is not
+ * allowed; INVALID_OPERATION, if this functionality is unsupported;
+ * BAD_VALUE if sensor event cannot be injected.
+ */
+ injectSensorData(Event event) generates (Result result);
+
+ /**
+ * Register direct report channel.
+ *
+ * Register a direct channel with supplied shared memory information. Upon
+ * return, the sensor hardware is responsible for resetting the memory
+ * content to initial value (depending on memory format settings).
+ *
+ * @param mem shared memory info data structure.
+ * @return result OK on success; BAD_VALUE if shared memory information is
+ * not consistent; NO_MEMORY if shared memory cannot be used by sensor
+ * system; INVALID_OPERATION if functionality is not supported.
+ * @return channelHandle a positive integer used for referencing registered
+ * direct channel (>0) in configureDirectReport and
+ * unregisterDirectChannel if result is OK, -1 otherwise.
+ */
+ registerDirectChannel(SharedMemInfo mem)
+ generates (Result result,
+ int32_t channelHandle);
+
+ /**
+ * Unregister direct report channel.
+ *
+ * Unregister a direct channel previously registered using
+ * registerDirectChannel, and remove all active sensor report configured in
+ * still active sensor report configured in the direct channel.
+ *
+ * @param channelHandle handle of direct channel to be unregistered.
+ * @return result OK if direct report is supported; INVALID_OPERATION
+ * otherwise.
+ */
+ unregisterDirectChannel(int32_t channelHandle) generates (Result result);
+
+ /**
+ * Configure direct sensor event report in direct channel.
+ *
+ * This function start, modify rate or stop direct report of a sensor in a
+ * certain direct channel.
+ *
+ * @param sensorHandle handle of sensor to be configured. When combined
+ * with STOP rate, sensorHandle can be -1 to denote all active sensors
+ * in the direct channel specified by channel Handle.
+ * @param channelHandle handle of direct channel to be configured.
+ * @param rate rate level, see RateLevel enum.
+ * @return result OK on success; BAD_VALUE if parameter is invalid (such as
+ * rate level is not supported by sensor, channelHandle does not exist,
+ * etc); INVALID_OPERATION if functionality is not supported.
+ * @return reportToken positive integer to identify multiple sensors of
+ * the same type in a single direct channel. Ignored if rate is STOP.
+ * See SharedMemFormat.
+ */
+ configDirectReport(
+ int32_t sensorHandle,
+ int32_t channelHandle,
+ RateLevel rate
+ ) generates (
+ Result result,
+ int32_t reportToken);
+};
diff --git a/sensors/2.0/ISensorsCallback.hal b/sensors/2.0/ISensorsCallback.hal
new file mode 100644
index 0000000..e0bd98f
--- /dev/null
+++ b/sensors/2.0/ISensorsCallback.hal
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors@2.0;
+
+import @1.0::SensorInfo;
+
+interface ISensorsCallback {
+ /**
+ * Notify the framework that new dynamic sensors have been connected.
+ *
+ * If a dynamic sensor was previously connected and has not been
+ * disconnected, then that sensor must not be included in sensorInfos.
+ *
+ * @param sensorInfos vector of SensorInfo for each dynamic sensor that
+ * was connected.
+ */
+ oneway onDynamicSensorsConnected(vec<SensorInfo> sensorInfos);
+
+ /**
+ * Notify the framework that previously connected dynamic sensors have been
+ * disconnected.
+ *
+ * If a dynamic sensor was previously disconnected and has not been
+ * reconnected, then that sensor must not be included in sensorHandles.
+ *
+ * The HAL must ensure that all sensor events from departing dynamic
+ * sensors have been written to the Event FMQ before calling
+ * onDynamicSensorsDisconnected.
+ *
+ * @param sensorHandles vector of sensor handles for each dynamic sensors
+ * that was disconnected.
+ */
+ oneway onDynamicSensorsDisconnected(vec<int32_t> sensorHandles);
+};
diff --git a/health/filesystem/1.0/types.hal b/sensors/2.0/types.hal
similarity index 61%
copy from health/filesystem/1.0/types.hal
copy to sensors/2.0/types.hal
index 00431f7..e1a029a 100644
--- a/health/filesystem/1.0/types.hal
+++ b/sensors/2.0/types.hal
@@ -14,26 +14,19 @@
* limitations under the License.
*/
-package android.hardware.health.filesystem@1.0;
+package android.hardware.sensors@2.0;
-/**
- * Status values for HAL methods.
- */
-enum Result : uint32_t {
+enum SensorTimeout : int32_t {
/**
- * Execution of the method is successful.
+ * The maximum number of seconds to wait for a message on the Wake Lock FMQ
+ * before automatically releasing any wake_lock held for a WAKE_UP event.
*/
- SUCCESS = 0,
+ WAKE_LOCK_SECONDS = 1,
+};
+
+enum EventQueueFlagBits : uint32_t {
/**
- * Execution of the method timed out.
+ * Used to notify the Event FMQ that events should be read and processed.
*/
- TIMEOUT,
- /**
- * An IO error is encountered when the HAL communicates with the device.
- */
- IO_ERROR,
- /**
- * An unknown error is encountered.
- */
- UNKNOWN_ERROR,
+ READ_AND_PROCESS = 1 << 0,
};
diff --git a/tests/safeunion/1.0/ISafeUnion.hal b/tests/safeunion/1.0/ISafeUnion.hal
index c38777a..f48248b 100644
--- a/tests/safeunion/1.0/ISafeUnion.hal
+++ b/tests/safeunion/1.0/ISafeUnion.hal
@@ -60,6 +60,9 @@
} k;
SmallSafeUnion l;
+
+ BitField m;
+ bitfield<BitField> n;
};
safe_union InterfaceTypeSafeUnion {
@@ -91,6 +94,8 @@
setJ(LargeSafeUnion myUnion, J j) generates (LargeSafeUnion myUnion);
setK(LargeSafeUnion myUnion, LargeSafeUnion.K k) generates (LargeSafeUnion myUnion);
setL(LargeSafeUnion myUnion, SmallSafeUnion l) generates (LargeSafeUnion myUnion);
+ setM(LargeSafeUnion myUnion, BitField m) generates (LargeSafeUnion myUnion);
+ setN(LargeSafeUnion myUnion, bitfield<BitField> m) generates (LargeSafeUnion myUnion);
newInterfaceTypeSafeUnion() generates (InterfaceTypeSafeUnion myUnion);
setInterfaceA(InterfaceTypeSafeUnion myUnion, uint32_t a) generates (InterfaceTypeSafeUnion myUnion);
diff --git a/tests/safeunion/1.0/default/SafeUnion.cpp b/tests/safeunion/1.0/default/SafeUnion.cpp
index c395664..4fb0974 100644
--- a/tests/safeunion/1.0/default/SafeUnion.cpp
+++ b/tests/safeunion/1.0/default/SafeUnion.cpp
@@ -153,6 +153,27 @@
return Void();
}
+Return<void> SafeUnion::setM(const LargeSafeUnion& myUnion, BitField m, setL_cb _hidl_cb) {
+ LOG(INFO) << "SERVER(SafeUnion) setM(myUnion, " << toString(m) << ")";
+
+ LargeSafeUnion myNewUnion = myUnion;
+ myNewUnion.m(m);
+
+ _hidl_cb(myNewUnion);
+ return Void();
+}
+
+Return<void> SafeUnion::setN(const LargeSafeUnion& myUnion, hidl_bitfield<BitField> n,
+ setL_cb _hidl_cb) {
+ LOG(INFO) << "SERVER(SafeUnion) setN(myUnion, " << n << ")";
+
+ LargeSafeUnion myNewUnion = myUnion;
+ myNewUnion.n(n);
+
+ _hidl_cb(myNewUnion);
+ return Void();
+}
+
Return<void> SafeUnion::newInterfaceTypeSafeUnion(newInterfaceTypeSafeUnion_cb _hidl_cb) {
LOG(INFO) << "SERVER(SafeUnion) newInterfaceTypeSafeUnion()";
diff --git a/tests/safeunion/1.0/default/SafeUnion.h b/tests/safeunion/1.0/default/SafeUnion.h
index e774e09..ee3a954 100644
--- a/tests/safeunion/1.0/default/SafeUnion.h
+++ b/tests/safeunion/1.0/default/SafeUnion.h
@@ -47,6 +47,9 @@
Return<void> setJ(const LargeSafeUnion& myUnion, const J& j, setJ_cb _hidl_cb) override;
Return<void> setK(const LargeSafeUnion& myUnion, const LargeSafeUnion::K& k, setK_cb _hidl_cb) override;
Return<void> setL(const LargeSafeUnion& myUnion, const SmallSafeUnion& l, setL_cb _hidl_cb) override;
+ Return<void> setM(const LargeSafeUnion& myUnion, BitField m, setL_cb _hidl_cb) override;
+ Return<void> setN(const LargeSafeUnion& myUnion, hidl_bitfield<BitField> n,
+ setL_cb _hidl_cb) override;
Return<void> newInterfaceTypeSafeUnion(newInterfaceTypeSafeUnion_cb _hidl_cb) override;
Return<void> setInterfaceA(const InterfaceTypeSafeUnion& myUnion, uint32_t a, setInterfaceA_cb _hidl_cb) override;
diff --git a/wifi/1.3/vts/OWNERS b/wifi/1.3/vts/OWNERS
new file mode 100644
index 0000000..8bfb148
--- /dev/null
+++ b/wifi/1.3/vts/OWNERS
@@ -0,0 +1,2 @@
+rpius@google.com
+etancohen@google.com
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..dbe77bd
--- /dev/null
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "VtsHalWifiV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalWifiV1_3TargetTest.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ ],
+}
diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
new file mode 100644
index 0000000..b410a48
--- /dev/null
+++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.3/IWifi.h>
+
+#include "wifi_hidl_test_utils.h"
+
+// Test environment for Wifi HIDL HAL.
+class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment {
+ public:
+ // get the test environment singleton
+ static WifiHidlEnvironment_1_3* Instance() {
+ static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3;
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<android::hardware::wifi::V1_3::IWifi>();
+ }
+
+ private:
+ WifiHidlEnvironment_1_3() {}
+};
+
+WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance();
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}