Merge "Fix hidl_string copy in boot VTS test" into oc-dev
diff --git a/automotive/evs/1.0/default/EvsEnumerator.cpp b/automotive/evs/1.0/default/EvsEnumerator.cpp
index 731e21b..b25d418 100644
--- a/automotive/evs/1.0/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.0/default/EvsEnumerator.cpp
@@ -99,7 +99,7 @@
}
// Construct a camera instance for the caller
- pActiveCamera = new EvsCamera(cameraId);
+ pActiveCamera = new EvsCamera(cameraId.c_str());
pRecord->activeInstance = pActiveCamera;
if (pActiveCamera == nullptr) {
ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index b8535bd..3c56159 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -25,6 +25,7 @@
common/src/SubscriptionManager.cpp \
common/src/VehicleHalManager.cpp \
common/src/VehicleObjectPool.cpp \
+ common/src/VehiclePropertyStore.cpp \
common/src/VehicleUtils.cpp \
LOCAL_C_INCLUDES := \
@@ -72,9 +73,10 @@
LOCAL_MODULE:= $(vhal_v2_0)-default-impl-lib
LOCAL_SRC_FILES:= \
- impl/vhal_v2_0/DefaultVehicleHal.cpp \
+ impl/vhal_v2_0/EmulatedVehicleHal.cpp \
+ impl/vhal_v2_0/VehicleEmulator.cpp \
impl/vhal_v2_0/PipeComm.cpp \
- impl/vhal_v2_0/SocketComm.cpp
+ impl/vhal_v2_0/SocketComm.cpp \
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/impl/vhal_v2_0
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index 95057cc..e6d292e 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -21,14 +21,16 @@
#include <iostream>
#include <vhal_v2_0/VehicleHalManager.h>
-#include <vhal_v2_0/DefaultVehicleHal.h>
+#include <vhal_v2_0/EmulatedVehicleHal.h>
using namespace android;
using namespace android::hardware;
using namespace android::hardware::automotive::vehicle::V2_0;
int main(int /* argc */, char* /* argv */ []) {
- auto hal = std::make_unique<impl::DefaultVehicleHal>();
+ auto store = std::make_unique<VehiclePropertyStore>();
+ auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
+ auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
auto service = std::make_unique<VehicleHalManager>(hal.get());
configureRpcThreadpool(1, true /* callerWillJoin */);
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
new file mode 100644
index 0000000..eda94b7
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_
+
+#include <cstdint>
+#include <unordered_map>
+#include <memory>
+#include <mutex>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/**
+ * Encapsulates work related to storing and accessing configuration, storing and modifying
+ * vehicle property values.
+ *
+ * VehiclePropertyValues stored in a sorted map thus it makes easier to get range of values, e.g.
+ * to get value for all areas for particular property.
+ *
+ * This class is thread-safe, however it uses blocking synchronization across all methods.
+ */
+class VehiclePropertyStore {
+public:
+ /* Function that used to calculate unique token for given VehiclePropValue */
+ using TokenFunction = std::function<int64_t(const VehiclePropValue& value)>;
+
+private:
+ struct RecordConfig {
+ VehiclePropConfig propConfig;
+ TokenFunction tokenFunction;
+ };
+
+ struct RecordId {
+ int32_t prop;
+ int32_t area;
+ int64_t token;
+
+ bool operator==(const RecordId& other) const;
+ bool operator<(const RecordId& other) const;
+ };
+
+ using PropertyMap = std::map<RecordId, VehiclePropValue>;
+ using PropertyMapRange = std::pair<PropertyMap::const_iterator, PropertyMap::const_iterator>;
+
+public:
+ void registerProperty(const VehiclePropConfig& config, TokenFunction tokenFunc = nullptr);
+
+ /* Stores provided value. Returns true if value was written returns false if config for
+ * example wasn't registered. */
+ bool writeValue(const VehiclePropValue& propValue);
+
+ void removeValue(const VehiclePropValue& propValue);
+ void removeValuesForProperty(int32_t propId);
+
+ std::vector<VehiclePropValue> readAllValues() const;
+ std::vector<VehiclePropValue> readValuesForProperty(int32_t propId) const;
+ std::unique_ptr<VehiclePropValue> readValueOrNull(const VehiclePropValue& request) const;
+ std::unique_ptr<VehiclePropValue> readValueOrNull(int32_t prop, int32_t area = 0,
+ int64_t token = 0) const;
+
+ std::vector<VehiclePropConfig> getAllConfigs() const;
+ const VehiclePropConfig* getConfigOrNull(int32_t propId) const;
+ const VehiclePropConfig* getConfigOrDie(int32_t propId) const;
+
+private:
+ RecordId getRecordIdLocked(const VehiclePropValue& valuePrototype) const;
+ const VehiclePropValue* getValueOrNullLocked(const RecordId& recId) const;
+ PropertyMapRange findRangeLocked(int32_t propId) const;
+
+private:
+ using MuxGuard = std::lock_guard<std::mutex>;
+ mutable std::mutex mLock;
+ std::unordered_map<int32_t /* VehicleProperty */, RecordConfig> mConfigs;
+
+ PropertyMap mPropertyValues; // Sorted map of RecordId : VehiclePropValue.
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif //android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
new file mode 100644
index 0000000..0e6b776
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "VehiclePropertyStore"
+#include <android/log.h>
+
+#include <common/include/vhal_v2_0/VehicleUtils.h>
+#include "VehiclePropertyStore.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
+ return prop == other.prop && area == other.area && token == other.token;
+}
+
+bool VehiclePropertyStore::RecordId::operator<(const VehiclePropertyStore::RecordId& other) const {
+ return prop < other.prop
+ || (prop == other.prop && area < other.area)
+ || (prop == other.prop && area == other.area && token < other.token);
+}
+
+void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
+ VehiclePropertyStore::TokenFunction tokenFunc) {
+ MuxGuard g(mLock);
+ mConfigs.insert({ config.prop, RecordConfig { config, tokenFunc } });
+}
+
+bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue) {
+ MuxGuard g(mLock);
+ if (!mConfigs.count(propValue.prop)) return false;
+
+ RecordId recId = getRecordIdLocked(propValue);
+ VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
+ if (valueToUpdate == nullptr) {
+ mPropertyValues.insert({ recId, propValue });
+ } else {
+ valueToUpdate->timestamp = propValue.timestamp;
+ valueToUpdate->value = propValue.value;
+ }
+ return true;
+}
+
+void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
+ MuxGuard g(mLock);
+ RecordId recId = getRecordIdLocked(propValue);
+ auto it = mPropertyValues.find(recId);
+ if (it != mPropertyValues.end()) {
+ mPropertyValues.erase(it);
+ }
+}
+
+void VehiclePropertyStore::removeValuesForProperty(int32_t propId) {
+ MuxGuard g(mLock);
+ auto range = findRangeLocked(propId);
+ mPropertyValues.erase(range.first, range.second);
+}
+
+std::vector<VehiclePropValue> VehiclePropertyStore::readAllValues() const {
+ MuxGuard g(mLock);
+ std::vector<VehiclePropValue> allValues;
+ allValues.reserve(mPropertyValues.size());
+ for (auto&& it : mPropertyValues) {
+ allValues.push_back(it.second);
+ }
+ return allValues;
+}
+
+std::vector<VehiclePropValue> VehiclePropertyStore::readValuesForProperty(int32_t propId) const {
+ std::vector<VehiclePropValue> values;
+ MuxGuard g(mLock);
+ auto range = findRangeLocked(propId);
+ for (auto it = range.first; it != range.second; ++it) {
+ values.push_back(it->second);
+ }
+
+ return values;
+}
+
+std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
+ const VehiclePropValue& request) const {
+ MuxGuard g(mLock);
+ RecordId recId = getRecordIdLocked(request);
+ const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
+ return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
+}
+
+std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
+ int32_t prop, int32_t area, int64_t token) const {
+ RecordId recId = {prop, isGlobalProp(prop) ? 0 : area, token };
+ MuxGuard g(mLock);
+ const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
+ return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
+}
+
+
+std::vector<VehiclePropConfig> VehiclePropertyStore::getAllConfigs() const {
+ MuxGuard g(mLock);
+ std::vector<VehiclePropConfig> configs;
+ configs.reserve(mConfigs.size());
+ for (auto&& recordConfigIt: mConfigs) {
+ configs.push_back(recordConfigIt.second.propConfig);
+ }
+ return configs;
+}
+
+const VehiclePropConfig* VehiclePropertyStore::getConfigOrNull(int32_t propId) const {
+ MuxGuard g(mLock);
+ auto recordConfigIt = mConfigs.find(propId);
+ return recordConfigIt != mConfigs.end() ? &recordConfigIt->second.propConfig : nullptr;
+}
+
+const VehiclePropConfig* VehiclePropertyStore::getConfigOrDie(int32_t propId) const {
+ auto cfg = getConfigOrNull(propId);
+ if (!cfg) {
+ ALOGW("%s: config not found for property: 0x%x", __func__, propId);
+ abort();
+ }
+ return cfg;
+}
+
+VehiclePropertyStore::RecordId VehiclePropertyStore::getRecordIdLocked(
+ const VehiclePropValue& valuePrototype) const {
+ RecordId recId = {
+ .prop = valuePrototype.prop,
+ .area = isGlobalProp(valuePrototype.prop) ? 0 : valuePrototype.areaId,
+ .token = 0
+ };
+
+ auto it = mConfigs.find(recId.prop);
+ if (it == mConfigs.end()) return {};
+
+ if (it->second.tokenFunction != nullptr) {
+ recId.token = it->second.tokenFunction(valuePrototype);
+ }
+ return recId;
+}
+
+const VehiclePropValue* VehiclePropertyStore::getValueOrNullLocked(
+ const VehiclePropertyStore::RecordId& recId) const {
+ auto it = mPropertyValues.find(recId);
+ return it == mPropertyValues.end() ? nullptr : &it->second;
+}
+
+VehiclePropertyStore::PropertyMapRange VehiclePropertyStore::findRangeLocked(int32_t propId) const {
+ // Based on the fact that mPropertyValues is a sorted map by RecordId.
+ auto beginIt = mPropertyValues.lower_bound( RecordId { propId, INT32_MIN, 0 });
+ auto endIt = mPropertyValues.lower_bound( RecordId { propId + 1, INT32_MIN, 0 });
+
+ return PropertyMapRange { beginIt, endIt };
+}
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
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 545de39..bf16a9b 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
@@ -33,176 +33,257 @@
toInt(VehicleProperty::HVAC_FAN_DIRECTION),
};
-const VehiclePropConfig kVehicleProperties[] = {
+struct ConfigDeclaration {
+ VehiclePropConfig config;
+
+ /* This value will be used as an initial value for the property. If this field is specified for
+ * property that supports multiple areas then it will be used for all areas unless particular
+ * area is overridden in initialAreaValue field. */
+ VehiclePropValue::RawValue initialValue;
+ /* Use initialAreaValues if it is necessary to specify different values per each area. */
+ std::map<int32_t, VehiclePropValue::RawValue> initialAreaValues;
+};
+
+const ConfigDeclaration kVehicleProperties[] {
{
- .prop = toInt(VehicleProperty::INFO_MAKE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
+ .config = {
+ .prop = toInt(VehicleProperty::INFO_MAKE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = { .stringValue = "Toy Vehicle" }
+ },
+ {
+ .config = {
+ .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .floatValues = {0.0f} }
},
{
- .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .config = {
+ .prop = toInt(VehicleProperty::CURRENT_GEAR),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = { toInt(VehicleGear::GEAR_PARK) } }
},
{
- .prop = toInt(VehicleProperty::CURRENT_GEAR),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .config = {
+ .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = {1} }
},
{
- .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .config = {
+ .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = {0} }
},
{
- .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ // TODO(bryaneyler): Ideally, this is generated dynamically from
+ // kHvacPowerProperties.
+ .configString = "0x12400500,0x12400501" // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
+ },
+ .initialValue = { .int32Values = {1} }
},
{
- .prop = toInt(VehicleProperty::HVAC_POWER_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas = toInt(VehicleAreaZone::ROW_1),
- // TODO(bryaneyler): Ideally, this is generated dynamically from
- // kHvacPowerProperties.
- .configString = "0x12400500,0x12400501" // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_DEFROSTER),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas =
+ VehicleAreaWindow::FRONT_WINDSHIELD
+ | VehicleAreaWindow::REAR_WINDSHIELD
+ },
+ .initialValue = { .int32Values = {0} } // Will be used for all areas.
},
{
- .prop = toInt(VehicleProperty::HVAC_DEFROSTER),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas =
- VehicleAreaWindow::FRONT_WINDSHIELD
- | VehicleAreaWindow::REAR_WINDSHIELD
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ },
+ .initialValue = { .int32Values = {1} }
},
{
- .prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_AC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ },
+ .initialValue = { .int32Values = {1} }
},
{
- .prop = toInt(VehicleProperty::HVAC_AC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_AUTO_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ },
+ .initialValue = { .int32Values = {1} }
},
{
- .prop = toInt(VehicleProperty::HVAC_AUTO_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1),
+ .minInt32Value = 1,
+ .maxInt32Value = 7
+ }
+ }
+ },
+ .initialValue = { .int32Values = {3} }
},
{
- .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas = toInt(VehicleAreaZone::ROW_1),
- .areaConfigs = {
- VehicleAreaConfig {
- .areaId = toInt(VehicleAreaZone::ROW_1),
- .minInt32Value = 1,
- .maxInt32Value = 7
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ },
+ .initialValue = { .int32Values = { toInt(VehicleHvacFanDirection::FACE) } }
+ },
+
+ {
+ .config = {
+ .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas =
+ VehicleAreaZone::ROW_1_LEFT
+ | VehicleAreaZone::ROW_1_RIGHT,
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .minFloatValue = 16,
+ .maxFloatValue = 32,
+ },
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+ .minFloatValue = 16,
+ .maxFloatValue = 32,
+ }
+ }
+ },
+ .initialAreaValues = {
+ {
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ { .floatValues = {16} }
+ }, {
+ toInt(VehicleAreaZone::ROW_1_RIGHT),
+ { .floatValues = {20} }
}
}
},
{
- .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ .config = {
+ .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+ .access = VehiclePropertyAccess::READ,
+ // TODO(bryaneyler): Support ON_CHANGE as well.
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ },
+ .initialValue = { .floatValues = {25.0f} }
},
{
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .supportedAreas =
- VehicleAreaZone::ROW_1_LEFT
- | VehicleAreaZone::ROW_1_RIGHT,
- .areaConfigs = {
- VehicleAreaConfig {
- .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
- .minFloatValue = 16,
- .maxFloatValue = 32,
- },
- VehicleAreaConfig {
- .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
- .minFloatValue = 16,
- .maxFloatValue = 32,
+ .config = {
+ .prop = toInt(VehicleProperty::NIGHT_MODE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = {0} }
+ },
+
+ {
+ .config = {
+ .prop = toInt(VehicleProperty::DRIVING_STATUS),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = { toInt(VehicleDrivingStatus::UNRESTRICTED) } }
+ },
+
+ {
+ .config = {
+ .prop = toInt(VehicleProperty::GEAR_SELECTION),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = { toInt(VehicleGear::GEAR_PARK) } }
+ },
+
+ {
+ .config = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = { .floatValues = { 123000.0f } } // In Milliliters
+ },
+
+ {
+ .config = {
+ .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .minInt32Value = 0,
+ .maxInt32Value = 10
+ }
}
- }
+ },
+ .initialValue = { .int32Values = {7} }
},
{
- .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
- .access = VehiclePropertyAccess::READ,
- // TODO(bryaneyler): Support ON_CHANGE as well.
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
+ .config = {
+ .prop = toInt(VehicleProperty::IGNITION_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = { .int32Values = { toInt(VehicleIgnitionState::ON) } }
},
{
- .prop = toInt(VehicleProperty::NIGHT_MODE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
-
- {
- .prop = toInt(VehicleProperty::DRIVING_STATUS),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
-
- {
- .prop = toInt(VehicleProperty::GEAR_SELECTION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
-
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
-
- {
- .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {
- VehicleAreaConfig {
- .minInt32Value = 0,
- .maxInt32Value = 10
- }
- }
- },
-
- {
- .prop = toInt(VehicleProperty::IGNITION_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
-
- {
- .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
- .maxSampleRate = 10, // 10 Hz, every 100 ms
+ .config = {
+ .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
+ .maxSampleRate = 10, // 10 Hz, every 100 ms
+ },
+ .initialValue = { .floatValues = {101.0f} }
}
};
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
deleted file mode 100644
index 03a65f3..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
- * Copyright (C) 2016 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 "DefaultVehicleHal_v2_0"
-#include <android/log.h>
-
-#include <algorithm>
-#include <android-base/properties.h>
-#include <cstdio>
-
-#include "DefaultVehicleHal.h"
-#include "PipeComm.h"
-#include "SocketComm.h"
-#include "VehicleHalProto.pb.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-void DefaultVehicleHal::doGetConfig(emulator::EmulatorMessage& rxMsg,
- emulator::EmulatorMessage& respMsg) {
- std::vector<VehiclePropConfig> configs = listProperties();
- emulator::VehiclePropGet getProp = rxMsg.prop(0);
-
- respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
- respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
-
- for (auto& config : configs) {
- // Find the config we are looking for
- if (config.prop == getProp.prop()) {
- emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
- populateProtoVehicleConfig(protoCfg, config);
- respMsg.set_status(emulator::RESULT_OK);
- break;
- }
- }
-}
-
-void DefaultVehicleHal::doGetConfigAll(emulator::EmulatorMessage& /* rxMsg */,
- emulator::EmulatorMessage& respMsg) {
- std::vector<VehiclePropConfig> configs = listProperties();
-
- respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
- respMsg.set_status(emulator::RESULT_OK);
-
- for (auto& config : configs) {
- emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
- populateProtoVehicleConfig(protoCfg, config);
- }
-}
-
-void DefaultVehicleHal::doGetProperty(emulator::EmulatorMessage& rxMsg,
- emulator::EmulatorMessage& respMsg) {
- int32_t areaId = 0;
- emulator::VehiclePropGet getProp = rxMsg.prop(0);
- int32_t propId = getProp.prop();
- emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
- VehiclePropValue* val;
-
- respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
-
- if (getProp.has_area_id()) {
- areaId = getProp.area_id();
- }
-
- {
- std::lock_guard<std::mutex> lock(mPropsMutex);
-
- val = getVehiclePropValueLocked(propId, areaId);
- if (val != nullptr) {
- emulator::VehiclePropValue* protoVal = respMsg.add_value();
- populateProtoVehiclePropValue(protoVal, val);
- status = emulator::RESULT_OK;
- }
- }
-
- respMsg.set_status(status);
-}
-
-void DefaultVehicleHal::doGetPropertyAll(emulator::EmulatorMessage& /* rxMsg */,
- emulator::EmulatorMessage& respMsg) {
- respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
- respMsg.set_status(emulator::RESULT_OK);
-
- {
- std::lock_guard<std::mutex> lock(mPropsMutex);
-
- for (auto& prop : mProps) {
- emulator::VehiclePropValue* protoVal = respMsg.add_value();
- populateProtoVehiclePropValue(protoVal, prop.second->get());
- }
- }
-}
-
-void DefaultVehicleHal::doSetProperty(emulator::EmulatorMessage& rxMsg,
- emulator::EmulatorMessage& respMsg) {
- emulator::VehiclePropValue protoVal = rxMsg.value(0);
- VehiclePropValue val;
-
- respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
-
- val.prop = protoVal.prop();
- val.areaId = protoVal.area_id();
- val.timestamp = elapsedRealtimeNano();
-
- // Copy value data if it is set. This automatically handles complex data types if needed.
- if (protoVal.has_string_value()) {
- val.value.stringValue = protoVal.string_value().c_str();
- }
-
- if (protoVal.has_bytes_value()) {
- std::vector<uint8_t> tmp(protoVal.bytes_value().begin(), protoVal.bytes_value().end());
- val.value.bytes = tmp;
- }
-
- if (protoVal.int32_values_size() > 0) {
- std::vector<int32_t> int32Values = std::vector<int32_t>(protoVal.int32_values_size());
- for (int i=0; i<protoVal.int32_values_size(); i++) {
- int32Values[i] = protoVal.int32_values(i);
- }
- val.value.int32Values = int32Values;
- }
-
- if (protoVal.int64_values_size() > 0) {
- std::vector<int64_t> int64Values = std::vector<int64_t>(protoVal.int64_values_size());
- for (int i=0; i<protoVal.int64_values_size(); i++) {
- int64Values[i] = protoVal.int64_values(i);
- }
- val.value.int64Values = int64Values;
- }
-
- if (protoVal.float_values_size() > 0) {
- std::vector<float> floatValues = std::vector<float>(protoVal.float_values_size());
- for (int i=0; i<protoVal.float_values_size(); i++) {
- floatValues[i] = protoVal.float_values(i);
- }
- val.value.floatValues = floatValues;
- }
-
- if (updateProperty(val) == StatusCode::OK) {
- // Send property up to VehicleHalManager via callback
- auto& pool = *getValuePool();
- VehiclePropValuePtr v = pool.obtain(val);
-
- doHalEvent(std::move(v));
- respMsg.set_status(emulator::RESULT_OK);
- } else {
- respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
- }
-}
-
-// This function should only be called while mPropsMutex is locked.
-VehiclePropValue* DefaultVehicleHal::getVehiclePropValueLocked(int32_t propId, int32_t areaId) {
- if (getPropArea(propId) == VehicleArea::GLOBAL) {
- // In VehicleHal, global properties have areaId = -1. We use 0.
- areaId = 0;
- }
-
- auto prop = mProps.find(std::make_pair(propId, areaId));
- if (prop != mProps.end()) {
- return prop->second->get();
- }
- ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __func__, propId, areaId);
- return nullptr;
-}
-
-void DefaultVehicleHal::parseRxProtoBuf(std::vector<uint8_t>& msg) {
- emulator::EmulatorMessage rxMsg;
- emulator::EmulatorMessage respMsg;
-
- if (rxMsg.ParseFromArray(msg.data(), msg.size())) {
- switch (rxMsg.msg_type()) {
- case emulator::GET_CONFIG_CMD:
- doGetConfig(rxMsg, respMsg);
- break;
- case emulator::GET_CONFIG_ALL_CMD:
- doGetConfigAll(rxMsg, respMsg);
- break;
- case emulator::GET_PROPERTY_CMD:
- doGetProperty(rxMsg, respMsg);
- break;
- case emulator::GET_PROPERTY_ALL_CMD:
- doGetPropertyAll(rxMsg, respMsg);
- break;
- case emulator::SET_PROPERTY_CMD:
- doSetProperty(rxMsg, respMsg);
- break;
- default:
- ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
- respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
- break;
- }
-
- // Send the reply
- txMsg(respMsg);
- } else {
- ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
- }
-}
-
-// Copies internal VehiclePropConfig data structure to protobuf VehiclePropConfig
-void DefaultVehicleHal::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
- const VehiclePropConfig& cfg) {
- protoCfg->set_prop(cfg.prop);
- protoCfg->set_access(toInt(cfg.access));
- protoCfg->set_change_mode(toInt(cfg.changeMode));
- protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
-
- if (!isGlobalProp(cfg.prop)) {
- protoCfg->set_supported_areas(cfg.supportedAreas);
- }
-
- for (auto& configElement : cfg.configArray) {
- protoCfg->add_config_array(configElement);
- }
-
- if (cfg.configString.size() > 0) {
- protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
- }
-
- // Populate the min/max values based on property type
- switch (getPropType(cfg.prop)) {
- case VehiclePropertyType::STRING:
- case VehiclePropertyType::BOOLEAN:
- case VehiclePropertyType::INT32_VEC:
- case VehiclePropertyType::FLOAT_VEC:
- case VehiclePropertyType::BYTES:
- case VehiclePropertyType::COMPLEX:
- // Do nothing. These types don't have min/max values
- break;
- case VehiclePropertyType::INT64:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
- aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
- }
- break;
- case VehiclePropertyType::FLOAT:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
- aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
- }
- break;
- case VehiclePropertyType::INT32:
- if (cfg.areaConfigs.size() > 0) {
- emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
- aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
- aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
- }
- break;
- default:
- ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
- break;
- }
-
- protoCfg->set_min_sample_rate(cfg.minSampleRate);
- protoCfg->set_max_sample_rate(cfg.maxSampleRate);
-}
-
-// Copies internal VehiclePropValue data structure to protobuf VehiclePropValue
-void DefaultVehicleHal::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
- const VehiclePropValue* val) {
- protoVal->set_prop(val->prop);
- protoVal->set_value_type(toInt(getPropType(val->prop)));
- protoVal->set_timestamp(val->timestamp);
- protoVal->set_area_id(val->areaId);
-
- // Copy value data if it is set.
- // - for bytes and strings, this is indicated by size > 0
- // - for int32, int64, and float, copy the values if vectors have data
- if (val->value.stringValue.size() > 0) {
- protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
- }
-
- if (val->value.bytes.size() > 0) {
- protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
- }
-
- for (auto& int32Value : val->value.int32Values) {
- protoVal->add_int32_values(int32Value);
- }
-
- for (auto& int64Value : val->value.int64Values) {
- protoVal->add_int64_values(int64Value);
- }
-
- for (auto& floatValue : val->value.floatValues) {
- protoVal->add_float_values(floatValue);
- }
-}
-
-void DefaultVehicleHal::rxMsg() {
- int numBytes = 0;
-
- while (mExit == 0) {
- std::vector<uint8_t> msg = mComm->read();
-
- if (msg.size() > 0) {
- // Received a message.
- parseRxProtoBuf(msg);
- } else {
- // This happens when connection is closed
- ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes,
- static_cast<int32_t>(msg.size()));
- break;
- }
- }
-}
-
-void DefaultVehicleHal::rxThread() {
- bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
-
- if (isEmulator) {
- // Initialize pipe to Emulator
- mComm.reset(new PipeComm);
- } else {
- // Initialize socket over ADB
- mComm.reset(new SocketComm);
- }
-
- int retVal = mComm->open();
-
- if (retVal == 0) {
- // Comms are properly opened
- while (mExit == 0) {
- retVal = mComm->connect();
-
- if (retVal >= 0) {
- rxMsg();
- }
-
- // Check every 100ms for a new connection
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- }
- }
-}
-
-// This function sets the default value of a property if we are interested in setting it.
-// TODO: Co-locate the default values with the configuration structure, to make it easier to
-// add new properties and their defaults.
-void DefaultVehicleHal::setDefaultValue(VehiclePropValue* prop) {
- switch (prop->prop) {
- case toInt(VehicleProperty::INFO_MAKE):
- prop->value.stringValue = "Default Car";
- break;
- case toInt(VehicleProperty::PERF_VEHICLE_SPEED):
- prop->value.floatValues[0] = 0;
- break;
- case toInt(VehicleProperty::CURRENT_GEAR):
- prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
- break;
- case toInt(VehicleProperty::PARKING_BRAKE_ON):
- prop->value.int32Values[0] = 1;
- break;
- case toInt(VehicleProperty::FUEL_LEVEL_LOW):
- prop->value.int32Values[0] = 0;
- break;
- case toInt(VehicleProperty::HVAC_POWER_ON):
- prop->value.int32Values[0] = 1;
- break;
- case toInt(VehicleProperty::HVAC_DEFROSTER):
- prop->value.int32Values[0] = 0;
- break;
- case toInt(VehicleProperty::HVAC_RECIRC_ON):
- prop->value.int32Values[0] = 1;
- break;
- case toInt(VehicleProperty::HVAC_AC_ON):
- prop->value.int32Values[0] = 1;
- break;
- case toInt(VehicleProperty::HVAC_AUTO_ON):
- prop->value.int32Values[0] = 1;
- break;
- case toInt(VehicleProperty::HVAC_FAN_SPEED):
- prop->value.int32Values[0] = 3;
- break;
- case toInt(VehicleProperty::HVAC_FAN_DIRECTION):
- prop->value.int32Values[0] = toInt(VehicleHvacFanDirection::FACE);
- break;
- case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
- prop->value.floatValues[0] = 16;
- break;
- case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE):
- prop->value.floatValues[0] = 25;
- break;
- case toInt(VehicleProperty::NIGHT_MODE):
- prop->value.int32Values[0] = 0;
- break;
- case toInt(VehicleProperty::DRIVING_STATUS):
- prop->value.int32Values[0] = toInt(VehicleDrivingStatus::UNRESTRICTED);
- break;
- case toInt(VehicleProperty::GEAR_SELECTION):
- prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
- break;
- case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
- prop->value.floatValues[0] = 123000.0f; // In milliliters
- break;
- case toInt(VehicleProperty::ENGINE_OIL_TEMP):
- prop->value.floatValues[0] = 101;
- break;
- case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
- prop->value.int32Values[0] = 7;
- break;
- case toInt(VehicleProperty::IGNITION_STATE):
- prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
- break;
- default:
- ALOGW("%s: propId=0x%x not found", __func__, prop->prop);
- break;
- }
-}
-
-// Transmit a reply back to the emulator
-void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) {
- int numBytes = txMsg.ByteSize();
- std::vector<uint8_t> msg(numBytes);
-
- if (txMsg.SerializeToArray(msg.data(), msg.size())) {
- int retVal = 0;
-
- // Send the message
- if (mExit == 0) {
- mComm->write(msg);
- }
-
- if (retVal < 0) {
- ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
- }
- } else {
- ALOGE("%s: SerializeToString failed!", __func__);
- }
-}
-
-// Updates the property value held in the HAL
-StatusCode DefaultVehicleHal::updateProperty(const VehiclePropValue& propValue) {
- auto propId = propValue.prop;
- auto areaId = propValue.areaId;
- StatusCode status = StatusCode::INVALID_ARG;
-
- {
- std::lock_guard<std::mutex> lock(mPropsMutex);
-
- VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
- if (internalPropValue != nullptr) {
- internalPropValue->value = propValue.value;
- internalPropValue->timestamp = propValue.timestamp;
- status = StatusCode::OK;
- }
- }
- return status;
-}
-
-VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
- const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
- auto areaId = requestedPropValue.areaId;
- auto& pool = *getValuePool();
- auto propId = requestedPropValue.prop;
- StatusCode status;
- VehiclePropValuePtr v = nullptr;
-
- switch (propId) {
- default:
- {
- std::lock_guard<std::mutex> lock(mPropsMutex);
-
- VehiclePropValue *internalPropValue = getVehiclePropValueLocked(propId, areaId);
- if (internalPropValue != nullptr) {
- v = pool.obtain(*internalPropValue);
- }
- }
-
- if (v != nullptr) {
- status = StatusCode::OK;
- } else {
- status = StatusCode::INVALID_ARG;
- }
- break;
- }
-
- *outStatus = status;
- return v;
-}
-
-StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
- auto propId = propValue.prop;
- StatusCode status;
- switch (propId) {
- default:
- if (mHvacPowerProps.count(propId)) {
- std::lock_guard<std::mutex> lock(mPropsMutex);
- auto hvacPowerOn = getVehiclePropValueLocked(toInt(VehicleProperty::HVAC_POWER_ON),
- toInt(VehicleAreaZone::ROW_1));
-
- if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
- && hvacPowerOn->value.int32Values[0] == 0) {
- status = StatusCode::NOT_AVAILABLE;
- break;
- }
- }
- status = updateProperty(propValue);
- if (status == StatusCode::OK) {
- // Send property update to emulator
- emulator::EmulatorMessage msg;
- emulator::VehiclePropValue *val = msg.add_value();
- populateProtoVehiclePropValue(val, &propValue);
- msg.set_status(emulator::RESULT_OK);
- msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
- txMsg(msg);
- }
- break;
- }
-
- return status;
-}
-
-V2_0::StatusCode DefaultVehicleHal::addCustomProperty(int32_t property,
- std::unique_ptr<CustomVehiclePropertyHandler>&& handler) {
- mProps[std::make_pair(property, 0)] = std::move(handler);
- ALOGW("%s: Added custom property: propId = 0x%x", __func__, property);
- return StatusCode::OK;
-}
-
-// Parse supported properties list and generate vector of property values to hold current values.
-void DefaultVehicleHal::onCreate() {
- // Initialize member variables
- mExit = 0;
-
- for (auto& prop : kHvacPowerProperties) {
- mHvacPowerProps.insert(prop);
- }
-
- // Get the list of configurations supported by this HAL
- std::vector<VehiclePropConfig> configs = listProperties();
-
- for (auto& cfg : configs) {
- VehiclePropertyType propType = getPropType(cfg.prop);
- int32_t supportedAreas = cfg.supportedAreas;
- int32_t vecSize;
-
- // Set the vector size based on property type
- switch (propType) {
- case VehiclePropertyType::BOOLEAN:
- case VehiclePropertyType::INT32:
- case VehiclePropertyType::INT64:
- case VehiclePropertyType::FLOAT:
- vecSize = 1;
- break;
- case VehiclePropertyType::INT32_VEC:
- case VehiclePropertyType::FLOAT_VEC:
- case VehiclePropertyType::BYTES:
- // TODO: Add proper support for these types
- vecSize = 1;
- break;
- case VehiclePropertyType::STRING:
- // Require individual handling
- vecSize = 0;
- break;
- case VehiclePropertyType::COMPLEX:
- switch (cfg.prop) {
- default:
- // Need to handle each complex property separately
- break;
- }
- continue;
- default:
- ALOGE("%s: propType=0x%x not found", __func__, propType);
- vecSize = 0;
- break;
- }
-
- // A global property will have supportedAreas = 0
- if (getPropArea(cfg.prop) == VehicleArea::GLOBAL) {
- supportedAreas = 0;
- }
-
- // This loop is a do-while so it executes at least once to handle global properties
- do {
- int32_t curArea = supportedAreas;
-
- // Clear the right-most bit of supportedAreas
- supportedAreas &= supportedAreas - 1;
-
- // Set curArea to the previously cleared bit
- curArea ^= supportedAreas;
-
- // Create a separate instance for each individual zone
- std::unique_ptr<VehiclePropValue> prop = createVehiclePropValue(propType, vecSize);
- prop->areaId = curArea;
- prop->prop = cfg.prop;
- setDefaultValue(prop.get());
- std::unique_ptr<CustomVehiclePropertyHandler> handler;
- handler.reset(new StoredValueCustomVehiclePropertyHandler());
- handler->set(*prop);
- mProps[std::make_pair(prop->prop, prop->areaId)] =
- std::move(handler);
- } while (supportedAreas != 0);
- }
-
- // Start rx thread
- mThread = std::thread(&DefaultVehicleHal::rxThread, this);
-}
-
-void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
- VehiclePropValuePtr v;
-
- auto& pool = *getValuePool();
-
- for (int32_t property : properties) {
- if (isContinuousProperty(property)) {
- // In real implementation this value should be read from sensor, random
- // value used for testing purpose only.
- std::lock_guard<std::mutex> lock(mPropsMutex);
-
- VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property);
- if (internalPropValue != nullptr) {
- v = pool.obtain(*internalPropValue);
- }
- if (VehiclePropertyType::FLOAT == getPropType(property)) {
- // Just get some randomness to continuous properties to see slightly differnt values
- // on the other end.
- v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5;
- }
- } else {
- ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
- }
-
- if (v.get()) {
- v->timestamp = elapsedRealtimeNano();
- doHalEvent(std::move(v));
- }
- }
-}
-
-StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t,
- float sampleRate) {
- ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate);
-
- if (isContinuousProperty(property)) {
- mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
- }
- return StatusCode::OK;
-}
-
-StatusCode DefaultVehicleHal::unsubscribe(int32_t property) {
- ALOGI("%s propId: 0x%x", __func__, property);
- if (isContinuousProperty(property)) {
- mRecurrentTimer.unregisterRecurrentEvent(property);
- }
- return StatusCode::OK;
-}
-
-const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const {
- auto it = mPropConfigMap.find(propId);
- return it == mPropConfigMap.end() ? nullptr : it->second;
-}
-
-bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const {
- const VehiclePropConfig* config = getPropConfig(propId);
- if (config == nullptr) {
- ALOGW("Config not found for property: 0x%x", propId);
- return false;
- }
- return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
-}
-
-} // impl
-
-} // namespace V2_0
-} // namespace vehicle
-} // namespace automotive
-} // namespace hardware
-} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
deleted file mode 100644
index c8310b3..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2016 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_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
-
-#include <map>
-#include <memory>
-#include <sys/socket.h>
-#include <thread>
-#include <unordered_set>
-
-#include <utils/SystemClock.h>
-
-#include "CommBase.h"
-#include "VehicleHalProto.pb.h"
-
-#include <vhal_v2_0/RecurrentTimer.h>
-#include <vhal_v2_0/VehicleHal.h>
-
-#include "DefaultConfig.h"
-#include "VehicleHalProto.pb.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-class DefaultVehicleHal : public VehicleHal {
-public:
- class CustomVehiclePropertyHandler {
- public:
- virtual VehiclePropValue* get() = 0;
- virtual StatusCode set(const VehiclePropValue& propValue) = 0;
- virtual ~CustomVehiclePropertyHandler() = default;
- };
-
-protected:
- class StoredValueCustomVehiclePropertyHandler :
- public CustomVehiclePropertyHandler {
- public:
- VehiclePropValue* get() override {
- return mPropValue.get();
- }
-
- StatusCode set(const VehiclePropValue& propValue) {
- *mPropValue = propValue;
- return StatusCode::OK;
- }
-private:
- std::unique_ptr<VehiclePropValue> mPropValue{new VehiclePropValue()};
-};
-
-public:
- DefaultVehicleHal() : mRecurrentTimer(
- std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) {
- for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
- mPropConfigMap[kVehicleProperties[i].prop] = &kVehicleProperties[i];
- }
- }
-
- ~DefaultVehicleHal() override {
- // Notify thread to finish and wait for it to terminate
- mExit = 1;
-
- // Close emulator socket if it is open
- mComm->stop();
-
- mThread.join();
- }
-
- std::vector<VehiclePropConfig> listProperties() override {
- return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties),
- std::end(kVehicleProperties));
- }
-
- VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
- StatusCode* outStatus) override;
-
- void onCreate() override;
-
- StatusCode set(const VehiclePropValue& propValue) override;
-
- StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
-
- StatusCode unsubscribe(int32_t property) override;
-
- /**
- * Add custom property information to this HAL instance.
- *
- * This is useful for allowing later versions of Vehicle HAL to coalesce
- * the list of properties they support with a previous version of the HAL.
- *
- * @param property The identifier of the new property
- * @param handler The object that will handle get/set requests
- * @return OK on success, an error code on failure
- */
- virtual StatusCode addCustomProperty(int32_t,
- std::unique_ptr<CustomVehiclePropertyHandler>&&);
-
- /**
- * Add custom property information to this HAL instance.
- *
- * This is useful for allowing later versions of Vehicle HAL to coalesce
- * the list of properties they support with a previous version of the HAL.
- *
- * @param initialValue The initial value for the new property. This is not
- * constant data, as later set() operations can change
- * this value at will
- * @return OK on success, an error code on failure
- */
- virtual StatusCode addCustomProperty(
- const VehiclePropValue& initialValue) {
- std::unique_ptr<CustomVehiclePropertyHandler> handler;
- handler.reset(new StoredValueCustomVehiclePropertyHandler());
- StatusCode setResponse = handler->set(initialValue);
- if (StatusCode::OK == setResponse) {
- return addCustomProperty(initialValue.prop,
- std::move(handler));
- } else {
- return setResponse;
- }
- }
-
-private:
- void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
- void doGetConfigAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
- void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
- void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
- void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
- VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0);
- const VehiclePropConfig* getPropConfig(int32_t propId) const;
- bool isContinuousProperty(int32_t propId) const;
- void parseRxProtoBuf(std::vector<uint8_t>& msg);
- void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
- const VehiclePropConfig& cfg);
- void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
- const VehiclePropValue* val);
- void setDefaultValue(VehiclePropValue* prop);
- void rxMsg();
- void rxThread();
- void txMsg(emulator::EmulatorMessage& txMsg);
- StatusCode updateProperty(const VehiclePropValue& propValue);
-
- constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
- return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
- }
-
- void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
-
-private:
- std::map<
- std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>,
- std::unique_ptr<CustomVehiclePropertyHandler>> mProps;
- std::atomic<int> mExit;
- std::unordered_set<int32_t> mHvacPowerProps;
- std::mutex mPropsMutex;
- std::thread mThread;
- std::unique_ptr<CommBase> mComm{nullptr};
- RecurrentTimer mRecurrentTimer;
- std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap;
-};
-
-} // impl
-
-} // namespace V2_0
-} // namespace vehicle
-} // namespace automotive
-} // namespace hardware
-} // namespace android
-
-
-#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
new file mode 100644
index 0000000..0ac6ada
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2016 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 "DefaultVehicleHal_v2_0"
+#include <android/log.h>
+
+#include "EmulatedVehicleHal.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
+ : mPropStore(propStore),
+ mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
+ mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
+ this, std::placeholders::_1)) {
+
+ for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
+ mPropStore->registerProperty(kVehicleProperties[i].config);
+ }
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
+ const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
+ VehiclePropValuePtr v = nullptr;
+
+ auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
+ if (internalPropValue != nullptr) {
+ v = getValuePool()->obtain(*internalPropValue);
+ }
+
+ *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
+ return v;
+}
+
+StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
+ if (mHvacPowerProps.count(propValue.prop)) {
+ auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
+ toInt(VehicleAreaZone::ROW_1));
+
+ if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
+ && hvacPowerOn->value.int32Values[0] == 0) {
+ return StatusCode::NOT_AVAILABLE;
+ }
+ }
+
+ if (!mPropStore->writeValue(propValue)) {
+ return StatusCode::INVALID_ARG;
+ }
+
+ getEmulatorOrDie()->doSetValueFromClient(propValue);
+
+ return StatusCode::OK;
+}
+
+// Parse supported properties list and generate vector of property values to hold current values.
+void EmulatedVehicleHal::onCreate() {
+ for (auto& it : kVehicleProperties) {
+ VehiclePropConfig cfg = it.config;
+ int32_t supportedAreas = cfg.supportedAreas;
+
+ // A global property will have supportedAreas = 0
+ if (isGlobalProp(cfg.prop)) {
+ supportedAreas = 0;
+ }
+
+ // This loop is a do-while so it executes at least once to handle global properties
+ do {
+ int32_t curArea = supportedAreas;
+ supportedAreas &= supportedAreas - 1; // Clear the right-most bit of supportedAreas.
+ curArea ^= supportedAreas; // Set curArea to the previously cleared bit.
+
+ // Create a separate instance for each individual zone
+ VehiclePropValue prop = {
+ .prop = cfg.prop,
+ .areaId = curArea,
+ };
+ if (it.initialAreaValues.size() > 0) {
+ auto valueForAreaIt = it.initialAreaValues.find(curArea);
+ if (valueForAreaIt != it.initialAreaValues.end()) {
+ prop.value = valueForAreaIt->second;
+ } else {
+ ALOGW("%s failed to get default value for prop 0x%x area 0x%x",
+ __func__, cfg.prop, curArea);
+ }
+ } else {
+ prop.value = it.initialValue;
+ }
+ mPropStore->writeValue(prop);
+
+ } while (supportedAreas != 0);
+ }
+}
+
+std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
+ return mPropStore->getAllConfigs();
+}
+
+void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
+ VehiclePropValuePtr v;
+
+ auto& pool = *getValuePool();
+
+ for (int32_t property : properties) {
+ if (isContinuousProperty(property)) {
+ auto internalPropValue = mPropStore->readValueOrNull(property);
+ if (internalPropValue != nullptr) {
+ v = pool.obtain(*internalPropValue);
+ }
+ } else {
+ ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
+ }
+
+ if (v.get()) {
+ v->timestamp = elapsedRealtimeNano();
+ doHalEvent(std::move(v));
+ }
+ }
+}
+
+StatusCode EmulatedVehicleHal::subscribe(int32_t property, int32_t,
+ float sampleRate) {
+ ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
+
+ if (isContinuousProperty(property)) {
+ mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
+ }
+ return StatusCode::OK;
+}
+
+StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
+ ALOGI("%s propId: 0x%x", __func__, property);
+ if (isContinuousProperty(property)) {
+ mRecurrentTimer.unregisterRecurrentEvent(property);
+ }
+ return StatusCode::OK;
+}
+
+bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
+ const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
+ if (config == nullptr) {
+ ALOGW("Config not found for property: 0x%x", propId);
+ return false;
+ }
+ return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
+}
+
+bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
+ if (mPropStore->writeValue(propValue)) {
+ doHalEvent(getValuePool()->obtain(propValue));
+ return true;
+ } else {
+ return false;
+ }
+}
+
+std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
+ return mPropStore->readAllValues();
+}
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
new file mode 100644
index 0000000..e0874e2
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_
+
+#include <map>
+#include <memory>
+#include <sys/socket.h>
+#include <thread>
+#include <unordered_set>
+
+#include <utils/SystemClock.h>
+
+#include "VehicleHalProto.pb.h"
+
+#include <vhal_v2_0/RecurrentTimer.h>
+#include <vhal_v2_0/VehicleHal.h>
+#include "vhal_v2_0/VehiclePropertyStore.h"
+
+#include "DefaultConfig.h"
+#include "VehicleHalProto.pb.h"
+#include "VehicleEmulator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
+class EmulatedVehicleHal : public EmulatedVehicleHalIface {
+public:
+ EmulatedVehicleHal(VehiclePropertyStore* propStore);
+ ~EmulatedVehicleHal() = default;
+
+ // Methods from VehicleHal
+ void onCreate() override;
+ std::vector<VehiclePropConfig> listProperties() override;
+ VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+ StatusCode* outStatus) override;
+ StatusCode set(const VehiclePropValue& propValue) override;
+ StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
+ StatusCode unsubscribe(int32_t property) override;
+
+ // Methods from EmulatedVehicleHalIface
+ bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;
+ std::vector<VehiclePropValue> getAllProperties() const override;
+
+private:
+ constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
+ return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
+ }
+
+ void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
+ bool isContinuousProperty(int32_t propId) const;
+
+private:
+ VehiclePropertyStore* mPropStore;
+ std::unordered_set<int32_t> mHvacPowerProps;
+ RecurrentTimer mRecurrentTimer;
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
new file mode 100644
index 0000000..38cb743
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "VehicleEmulator_v2_0"
+#include <android/log.h>
+
+#include <algorithm>
+#include <android-base/properties.h>
+#include <utils/SystemClock.h>
+
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "PipeComm.h"
+#include "SocketComm.h"
+
+#include "VehicleEmulator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+std::unique_ptr<CommBase> CommFactory::create() {
+ bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
+
+ if (isEmulator) {
+ return std::make_unique<PipeComm>();
+ } else {
+ return std::make_unique<SocketComm>();
+ }
+}
+
+VehicleEmulator::~VehicleEmulator() {
+ mExit = true; // Notify thread to finish and wait for it to terminate.
+ mComm->stop(); // Close emulator socket if it is open.
+ if (mThread.joinable()) mThread.join();
+}
+
+void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
+ emulator::EmulatorMessage msg;
+ emulator::VehiclePropValue *val = msg.add_value();
+ populateProtoVehiclePropValue(val, &propValue);
+ msg.set_status(emulator::RESULT_OK);
+ msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+ txMsg(msg);
+}
+
+void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage& rxMsg,
+ VehicleEmulator::EmulatorMessage& respMsg) {
+ std::vector<VehiclePropConfig> configs = mHal->listProperties();
+ emulator::VehiclePropGet getProp = rxMsg.prop(0);
+
+ respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
+ respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+
+ for (auto& config : configs) {
+ // Find the config we are looking for
+ if (config.prop == getProp.prop()) {
+ emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ populateProtoVehicleConfig(protoCfg, config);
+ respMsg.set_status(emulator::RESULT_OK);
+ break;
+ }
+ }
+}
+
+void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage& /* rxMsg */,
+ VehicleEmulator::EmulatorMessage& respMsg) {
+ std::vector<VehiclePropConfig> configs = mHal->listProperties();
+
+ respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
+ respMsg.set_status(emulator::RESULT_OK);
+
+ for (auto& config : configs) {
+ emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ populateProtoVehicleConfig(protoCfg, config);
+ }
+}
+
+void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage& rxMsg,
+ VehicleEmulator::EmulatorMessage& respMsg) {
+ int32_t areaId = 0;
+ emulator::VehiclePropGet getProp = rxMsg.prop(0);
+ int32_t propId = getProp.prop();
+ emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+
+ respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+
+ if (getProp.has_area_id()) {
+ areaId = getProp.area_id();
+ }
+
+ {
+ VehiclePropValue request = { .prop = propId, .areaId = areaId };
+ StatusCode halStatus;
+ auto val = mHal->get(request, &halStatus);
+ if (val != nullptr) {
+ emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ populateProtoVehiclePropValue(protoVal, val.get());
+ status = emulator::RESULT_OK;
+ }
+ }
+
+ respMsg.set_status(status);
+}
+
+void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage& /* rxMsg */,
+ VehicleEmulator::EmulatorMessage& respMsg) {
+ respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
+ respMsg.set_status(emulator::RESULT_OK);
+
+ {
+ for (const auto& prop : mHal->getAllProperties()) {
+ emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ populateProtoVehiclePropValue(protoVal, &prop);
+ }
+ }
+}
+
+void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage& rxMsg,
+ VehicleEmulator::EmulatorMessage& respMsg) {
+ emulator::VehiclePropValue protoVal = rxMsg.value(0);
+ VehiclePropValue val = {
+ .prop = protoVal.prop(),
+ .areaId = protoVal.area_id(),
+ .timestamp = elapsedRealtimeNano(),
+ };
+
+ respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+
+ // Copy value data if it is set. This automatically handles complex data types if needed.
+ if (protoVal.has_string_value()) {
+ val.value.stringValue = protoVal.string_value().c_str();
+ }
+
+ if (protoVal.has_bytes_value()) {
+ val.value.bytes = std::vector<uint8_t> { protoVal.bytes_value().begin(),
+ protoVal.bytes_value().end() };
+ }
+
+ if (protoVal.int32_values_size() > 0) {
+ val.value.int32Values = std::vector<int32_t> { protoVal.int32_values().begin(),
+ protoVal.int32_values().end() };
+ }
+
+ if (protoVal.int64_values_size() > 0) {
+ val.value.int64Values = std::vector<int64_t> { protoVal.int64_values().begin(),
+ protoVal.int64_values().end() };
+ }
+
+ if (protoVal.float_values_size() > 0) {
+ val.value.floatValues = std::vector<float> { protoVal.float_values().begin(),
+ protoVal.float_values().end() };
+ }
+
+ bool halRes = mHal->setPropertyFromVehicle(val);
+ respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
+}
+
+void VehicleEmulator::txMsg(emulator::EmulatorMessage& txMsg) {
+ int numBytes = txMsg.ByteSize();
+ std::vector<uint8_t> msg(static_cast<size_t>(numBytes));
+
+ if (!txMsg.SerializeToArray(msg.data(), static_cast<int32_t>(msg.size()))) {
+ ALOGE("%s: SerializeToString failed!", __func__);
+ return;
+ }
+
+ if (mExit) {
+ ALOGW("%s: unable to transmit a message, connection closed", __func__);
+ return;
+ }
+
+ // Send the message
+ int retVal = mComm->write(msg);
+ if (retVal < 0) {
+ ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
+ }
+}
+
+void VehicleEmulator::parseRxProtoBuf(std::vector<uint8_t>& msg) {
+ emulator::EmulatorMessage rxMsg;
+ emulator::EmulatorMessage respMsg;
+
+ if (rxMsg.ParseFromArray(msg.data(), static_cast<int32_t>(msg.size()))) {
+ switch (rxMsg.msg_type()) {
+ case emulator::GET_CONFIG_CMD:
+ doGetConfig(rxMsg, respMsg);
+ break;
+ case emulator::GET_CONFIG_ALL_CMD:
+ doGetConfigAll(rxMsg, respMsg);
+ break;
+ case emulator::GET_PROPERTY_CMD:
+ doGetProperty(rxMsg, respMsg);
+ break;
+ case emulator::GET_PROPERTY_ALL_CMD:
+ doGetPropertyAll(rxMsg, respMsg);
+ break;
+ case emulator::SET_PROPERTY_CMD:
+ doSetProperty(rxMsg, respMsg);
+ break;
+ default:
+ ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
+ respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+ break;
+ }
+
+ // Send the reply
+ txMsg(respMsg);
+ } else {
+ ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
+ }
+}
+
+void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+ const VehiclePropConfig& cfg) {
+ protoCfg->set_prop(cfg.prop);
+ protoCfg->set_access(toInt(cfg.access));
+ protoCfg->set_change_mode(toInt(cfg.changeMode));
+ protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+ if (!isGlobalProp(cfg.prop)) {
+ protoCfg->set_supported_areas(cfg.supportedAreas);
+ }
+
+ for (auto& configElement : cfg.configArray) {
+ protoCfg->add_config_array(configElement);
+ }
+
+ if (cfg.configString.size() > 0) {
+ protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+ }
+
+ // Populate the min/max values based on property type
+ switch (getPropType(cfg.prop)) {
+ case VehiclePropertyType::STRING:
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32_VEC:
+ case VehiclePropertyType::FLOAT_VEC:
+ case VehiclePropertyType::BYTES:
+ case VehiclePropertyType::COMPLEX:
+ // Do nothing. These types don't have min/max values
+ break;
+ case VehiclePropertyType::INT64:
+ if (cfg.areaConfigs.size() > 0) {
+ emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+ aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
+ aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
+ }
+ break;
+ case VehiclePropertyType::FLOAT:
+ if (cfg.areaConfigs.size() > 0) {
+ emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+ aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
+ aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
+ }
+ break;
+ case VehiclePropertyType::INT32:
+ if (cfg.areaConfigs.size() > 0) {
+ emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+ aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
+ aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
+ }
+ break;
+ default:
+ ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
+ break;
+ }
+
+ protoCfg->set_min_sample_rate(cfg.minSampleRate);
+ protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+}
+
+void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+ const VehiclePropValue* val) {
+ protoVal->set_prop(val->prop);
+ protoVal->set_value_type(toInt(getPropType(val->prop)));
+ protoVal->set_timestamp(val->timestamp);
+ protoVal->set_area_id(val->areaId);
+
+ // Copy value data if it is set.
+ // - for bytes and strings, this is indicated by size > 0
+ // - for int32, int64, and float, copy the values if vectors have data
+ if (val->value.stringValue.size() > 0) {
+ protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
+ }
+
+ if (val->value.bytes.size() > 0) {
+ protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
+ }
+
+ for (auto& int32Value : val->value.int32Values) {
+ protoVal->add_int32_values(int32Value);
+ }
+
+ for (auto& int64Value : val->value.int64Values) {
+ protoVal->add_int64_values(int64Value);
+ }
+
+ for (auto& floatValue : val->value.floatValues) {
+ protoVal->add_float_values(floatValue);
+ }
+}
+
+void VehicleEmulator::rxMsg() {
+ while (!mExit) {
+ std::vector<uint8_t> msg = mComm->read();
+
+ if (msg.size() > 0) {
+ // Received a message.
+ parseRxProtoBuf(msg);
+ } else {
+ // This happens when connection is closed
+ ALOGD("%s: msgSize=%zu", __func__, msg.size());
+ break;
+ }
+ }
+}
+
+void VehicleEmulator::rxThread() {
+ if (mExit) return;
+
+ int retVal = mComm->open();
+ if (retVal != 0) mExit = true;
+
+ // Comms are properly opened
+ while (!mExit) {
+ retVal = mComm->connect();
+
+ if (retVal >= 0) {
+ rxMsg();
+ }
+
+ // Check every 100ms for a new connection
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+}
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
new file mode 100644
index 0000000..9a75ddc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
+
+#include <memory>
+#include <thread>
+#include <vector>
+#include "vhal_v2_0/VehicleHal.h"
+
+#include "CommBase.h"
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class VehicleEmulator; // Forward declaration.
+
+/** Extension of VehicleHal that used by VehicleEmulator. */
+class EmulatedVehicleHalIface : public VehicleHal {
+public:
+ virtual bool setPropertyFromVehicle(const VehiclePropValue& propValue) = 0;
+ virtual std::vector<VehiclePropValue> getAllProperties() const = 0;
+
+ void registerEmulator(VehicleEmulator* emulator) {
+ ALOGI("%s, emulator: %p", __func__, emulator);
+ std::lock_guard<std::mutex> g(mEmulatorLock);
+ mEmulator = emulator;
+ }
+
+protected:
+ VehicleEmulator* getEmulatorOrDie() {
+ std::lock_guard<std::mutex> g(mEmulatorLock);
+ ALOGI("%s, emulator: %p", __func__, mEmulator);
+ assert(mEmulator != nullptr);
+ return mEmulator;
+ }
+
+private:
+ mutable std::mutex mEmulatorLock;
+ VehicleEmulator* mEmulator;
+};
+
+struct CommFactory {
+ static std::unique_ptr<CommBase> create();
+};
+
+/**
+ * Emulates vehicle by providing controlling interface from host side either through ADB or Pipe.
+ */
+class VehicleEmulator {
+public:
+ VehicleEmulator(EmulatedVehicleHalIface* hal,
+ std::unique_ptr<CommBase> comm = CommFactory::create())
+ : mHal { hal },
+ mComm(comm.release()),
+ mThread { &VehicleEmulator::rxThread, this} {
+ mHal->registerEmulator(this);
+ }
+ virtual ~VehicleEmulator();
+
+ void doSetValueFromClient(const VehiclePropValue& propValue);
+
+private:
+ using EmulatorMessage = emulator::EmulatorMessage;
+
+ void doGetConfig(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
+ void doGetConfigAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
+ void doGetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
+ void doGetPropertyAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
+ void doSetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
+ void txMsg(emulator::EmulatorMessage& txMsg);
+ void parseRxProtoBuf(std::vector<uint8_t>& msg);
+ void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+ const VehiclePropConfig& cfg);
+ void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+ const VehiclePropValue* val);
+ void rxMsg();
+ void rxThread();
+
+private:
+ std::atomic<bool> mExit { false };
+ EmulatedVehicleHalIface* mHal;
+ std::unique_ptr<CommBase> mComm;
+ std::thread mThread;
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
diff --git a/automotive/vehicle/2.1/default/Android.mk b/automotive/vehicle/2.1/default/Android.mk
index 51cb146..32ec456 100644
--- a/automotive/vehicle/2.1/default/Android.mk
+++ b/automotive/vehicle/2.1/default/Android.mk
@@ -49,7 +49,7 @@
LOCAL_MODULE:= $(vhal_v2_1)-default-impl-lib
LOCAL_SRC_FILES:= \
- impl/vhal_v2_1/DefaultVehicleHal.cpp \
+ impl/vhal_v2_1/EmulatedVehicleHal.cpp \
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/impl/vhal_v2_1 \
diff --git a/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h b/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h
index 945e3e0..6c44626 100644
--- a/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h
+++ b/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h
@@ -55,8 +55,7 @@
const std::vector<uint8_t>& getSensorsBitmask() const;
// Given a stringValue, fill in a VehiclePropValue
- void fillPropValue(V2_0::VehiclePropValue *propValue,
- std::string dtc) const;
+ void fillPropValue(const std::string& dtc, V2_0::VehiclePropValue *propValue) const;
private:
class BitmaskInVector {
diff --git a/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp b/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp
index b07717b..f4c63a9 100644
--- a/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp
+++ b/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp
@@ -99,8 +99,8 @@
return mSensorsBitmask.getBitmask();
}
-void Obd2SensorStore::fillPropValue(V2_0::VehiclePropValue *propValue,
- std::string dtc) const {
+void Obd2SensorStore::fillPropValue(const std::string& dtc,
+ V2_0::VehiclePropValue *propValue) const {
propValue->timestamp = elapsedRealtimeNano();
propValue->value.int32Values = getIntegerSensors();
propValue->value.floatValues = getFloatSensors();
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
index 6bdec59..aa9aa3c 100644
--- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
@@ -28,41 +28,50 @@
namespace impl {
+// Some handy constants to avoid conversions from enum to int.
+constexpr int OBD2_LIVE_FRAME = (int) V2_1::VehicleProperty::OBD2_LIVE_FRAME;
+constexpr int OBD2_FREEZE_FRAME = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME;
+constexpr int OBD2_FREEZE_FRAME_INFO = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO;
+constexpr int OBD2_FREEZE_FRAME_CLEAR = (int) V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR;
+constexpr int VEHICLE_MAP_SERVICE = (int) V2_1::VehicleProperty::VEHICLE_MAP_SERVICE;
+constexpr int WHEEL_TICK = (int) V2_1::VehicleProperty::WHEEL_TICK;
+
+
const V2_0::VehiclePropConfig kVehicleProperties[] = {
{
- .prop = V2_0::toInt(V2_1::VehicleProperty::WHEEL_TICK),
+ .prop = WHEEL_TICK,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::CONTINUOUS,
},
{
- .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME),
+ .prop = OBD2_LIVE_FRAME,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {0,0}
},
{
- .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME),
+ .prop = OBD2_FREEZE_FRAME,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {0,0}
},
{
- .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO),
+ .prop = OBD2_FREEZE_FRAME_INFO,
.access = V2_0::VehiclePropertyAccess::READ,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
},
{
- .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR),
+ .prop = OBD2_FREEZE_FRAME_CLEAR,
.access = V2_0::VehiclePropertyAccess::WRITE,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
},
{
- .prop = V2_0::toInt(VehicleProperty::VEHICLE_MAP_SERVICE),
+ .prop = VEHICLE_MAP_SERVICE,
.access = V2_0::VehiclePropertyAccess::READ_WRITE,
.changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
}
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h
deleted file mode 100644
index af21138..0000000
--- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2016 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_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_
-#define android_hardware_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_
-
-#include <memory>
-
-#include <utils/SystemClock.h>
-
-#include <vhal_v2_0/VehicleHal.h>
-#include <vhal_v2_0/DefaultVehicleHal.h>
-#include <vhal_v2_1/Obd2SensorStore.h>
-
-#include "DefaultConfig.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_1 {
-
-namespace impl {
-
-using namespace std::placeholders;
-
-class DefaultVehicleHal : public V2_0::VehicleHal {
-public:
- DefaultVehicleHal(V2_0::impl::DefaultVehicleHal* vhal20) :
- mVehicleHal20(vhal20) {}
-
- std::vector<V2_0::VehiclePropConfig> listProperties() override {
- std::vector<V2_0::VehiclePropConfig> propConfigs(mVehicleHal20->listProperties());
-
- // Join Vehicle Hal 2.0 and 2.1 configs.
- propConfigs.insert(propConfigs.end(),
- std::begin(kVehicleProperties),
- std::end(kVehicleProperties));
-
- return propConfigs;
- }
-
- VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue,
- V2_0::StatusCode* outStatus) override;
-
- V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override;
-
- V2_0::StatusCode subscribe(int32_t property,
- int32_t areas,
- float sampleRate) override {
- return mVehicleHal20->subscribe(property, areas, sampleRate);
- }
-
- V2_0::StatusCode unsubscribe(int32_t property) override {
- return mVehicleHal20->unsubscribe(property);
- }
-
- void onCreate() override;
-
-private:
- void initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig,
- V2_0::VehiclePropValue* liveObd2Frame);
- void initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig);
- V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue,
- V2_0::VehiclePropValue* v);
- V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *v);
- V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue);
-
-private:
- V2_0::impl::DefaultVehicleHal* mVehicleHal20;
- std::vector<std::unique_ptr<V2_0::VehiclePropValue>> mFreezeObd2Frames;
-};
-
-} // impl
-
-} // namespace V2_1
-} // namespace vehicle
-} // namespace automotive
-} // namespace hardware
-} // namespace android
-
-
-#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp
similarity index 63%
rename from automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp
rename to automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp
index b147ce7..ae7f416 100644
--- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp
@@ -21,7 +21,7 @@
#include <netinet/in.h>
#include <sys/socket.h>
-#include "DefaultVehicleHal.h"
+#include "EmulatedVehicleHal.h"
#include "VehicleHalProto.pb.h"
#define DEBUG_SOCKET (33452)
@@ -120,118 +120,103 @@
return sensorStore;
}
-void DefaultVehicleHal::initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig,
- V2_0::VehiclePropValue* liveObd2Frame) {
- auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0],
- propConfig.configArray[1]);
- sensorStore->fillPropValue(liveObd2Frame, "");
- liveObd2Frame->prop = V2_0::toInt(VehicleProperty::OBD2_LIVE_FRAME);
+void EmulatedVehicleHal::initObd2LiveFrame(const V2_0::VehiclePropConfig& propConfig) {
+ auto liveObd2Frame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
+ auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
+ static_cast<size_t>(propConfig.configArray[1]));
+ sensorStore->fillPropValue("", liveObd2Frame.get());
+ liveObd2Frame->prop = OBD2_LIVE_FRAME;
+
+ mPropStore->writeValue(*liveObd2Frame);
}
-void DefaultVehicleHal::initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig) {
- auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0],
- propConfig.configArray[1]);
+void EmulatedVehicleHal::initObd2FreezeFrame(const V2_0::VehiclePropConfig& propConfig) {
+ auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
+ static_cast<size_t>(propConfig.configArray[1]));
- mFreezeObd2Frames.push_back(
- createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
- mFreezeObd2Frames.push_back(
- createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
- mFreezeObd2Frames.push_back(
- createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
-
- sensorStore->fillPropValue(mFreezeObd2Frames[0].get(), "P0070");
- sensorStore->fillPropValue(mFreezeObd2Frames[1].get(), "P0102");
- sensorStore->fillPropValue(mFreezeObd2Frames[2].get(), "P0123");
+ static std::vector<std::string> sampleDtcs = { "P0070", "P0102" "P0123" };
+ for (auto&& dtc : sampleDtcs) {
+ auto freezeFrame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
+ sensorStore->fillPropValue(dtc, freezeFrame.get());
+ mPropStore->writeValue(*freezeFrame);
+ }
}
-template<typename Iterable>
-typename Iterable::const_iterator findPropValueAtTimestamp(
- const Iterable& frames,
- int64_t timestamp) {
- return std::find_if(frames.begin(),
- frames.end(),
- [timestamp] (const std::unique_ptr<V2_0::VehiclePropValue>&
- propValue) -> bool {
- return propValue->timestamp == timestamp;
- });
-}
-
-V2_0::StatusCode DefaultVehicleHal::fillObd2FreezeFrame(
+V2_0::StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(
const V2_0::VehiclePropValue& requestedPropValue,
- V2_0::VehiclePropValue* v) {
+ V2_0::VehiclePropValue* outValue) {
if (requestedPropValue.value.int64Values.size() != 1) {
ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
return V2_0::StatusCode::INVALID_ARG;
}
auto timestamp = requestedPropValue.value.int64Values[0];
- auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames,
- timestamp);
- if(mFreezeObd2Frames.end() == freezeFrameIter) {
+ auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
+ if(freezeFrame == nullptr) {
ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
return V2_0::StatusCode::INVALID_ARG;
}
- const auto& freezeFrame = *freezeFrameIter;
- v->prop = V2_0::toInt(VehicleProperty::OBD2_FREEZE_FRAME);
- v->value.int32Values = freezeFrame->value.int32Values;
- v->value.floatValues = freezeFrame->value.floatValues;
- v->value.bytes = freezeFrame->value.bytes;
- v->value.stringValue = freezeFrame->value.stringValue;
- v->timestamp = freezeFrame->timestamp;
+ outValue->prop = OBD2_FREEZE_FRAME;
+ outValue->value.int32Values = freezeFrame->value.int32Values;
+ outValue->value.floatValues = freezeFrame->value.floatValues;
+ outValue->value.bytes = freezeFrame->value.bytes;
+ outValue->value.stringValue = freezeFrame->value.stringValue;
+ outValue->timestamp = freezeFrame->timestamp;
return V2_0::StatusCode::OK;
}
-V2_0::StatusCode DefaultVehicleHal::clearObd2FreezeFrames(
- const V2_0::VehiclePropValue& propValue) {
+V2_0::StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue) {
if (propValue.value.int64Values.size() == 0) {
- mFreezeObd2Frames.clear();
+ mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
return V2_0::StatusCode::OK;
} else {
for(int64_t timestamp: propValue.value.int64Values) {
- auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames,
- timestamp);
- if(mFreezeObd2Frames.end() == freezeFrameIter) {
+ auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
+ if(freezeFrame == nullptr) {
ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
return V2_0::StatusCode::INVALID_ARG;
}
- mFreezeObd2Frames.erase(freezeFrameIter);
+ mPropStore->removeValue(*freezeFrame);
}
}
return V2_0::StatusCode::OK;
}
-V2_0::StatusCode DefaultVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* v) {
+V2_0::StatusCode EmulatedVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* outValue) {
std::vector<int64_t> timestamps;
- for(const auto& freezeFrame: mFreezeObd2Frames) {
- timestamps.push_back(freezeFrame->timestamp);
+ for(const auto& freezeFrame: mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) {
+ timestamps.push_back(freezeFrame.timestamp);
}
- v->value.int64Values = timestamps;
+ outValue->value.int64Values = timestamps;
return V2_0::StatusCode::OK;
}
-void DefaultVehicleHal::onCreate() {
- mVehicleHal20->init(getValuePool(),
- std::bind(&DefaultVehicleHal::doHalEvent, this, _1),
- std::bind(&DefaultVehicleHal::doHalPropertySetError, this, _1, _2, _3));
+void EmulatedVehicleHal::onCreate() {
+ V2_0::impl::EmulatedVehicleHal::onCreate();
- std::vector<V2_0::VehiclePropConfig> configs = listProperties();
- for (auto& cfg : configs) {
- switch(cfg.prop) {
- case V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME): {
- auto liveObd2Frame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
- initObd2LiveFrame(cfg, liveObd2Frame.get());
- mVehicleHal20->addCustomProperty(*liveObd2Frame);
+ initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
+ initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
+}
+
+void EmulatedVehicleHal::initStaticConfig() {
+ for (auto&& cfg = std::begin(kVehicleProperties); cfg != std::end(kVehicleProperties); ++cfg) {
+ V2_0::VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
+
+ switch (cfg->prop) {
+ case OBD2_FREEZE_FRAME: {
+ tokenFunction = [] (const V2_0::VehiclePropValue& propValue) {
+ return propValue.timestamp;
+ };
+ break;
}
- break;
- case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME):
- initObd2FreezeFrame(cfg);
- break;
default:
break;
}
+
+ mPropStore->registerProperty(*cfg, tokenFunction);
}
}
-DefaultVehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
+EmulatedVehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
const V2_0::VehiclePropValue& requestedPropValue,
V2_0::StatusCode* outStatus) {
@@ -240,34 +225,30 @@
auto& pool = *getValuePool();
switch (propId) {
- case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME):
+ case OBD2_FREEZE_FRAME:
v = pool.obtainComplex();
*outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
return v;
- case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO):
+ case OBD2_FREEZE_FRAME_INFO:
v = pool.obtainComplex();
*outStatus = fillObd2DtcInfo(v.get());
return v;
default:
- return mVehicleHal20->get(requestedPropValue, outStatus);
+ return V2_0::impl::EmulatedVehicleHal::get(requestedPropValue, outStatus);
}
}
-V2_0::StatusCode DefaultVehicleHal::set(
- const V2_0::VehiclePropValue& propValue) {
-
+V2_0::StatusCode EmulatedVehicleHal::set(const V2_0::VehiclePropValue& propValue) {
auto propId = propValue.prop;
switch (propId) {
- case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR):
+ case OBD2_FREEZE_FRAME_CLEAR:
return clearObd2FreezeFrames(propValue);
- break;
- case V2_0::toInt(V2_1::VehicleProperty::VEHICLE_MAP_SERVICE):
+ case VEHICLE_MAP_SERVICE:
// Placeholder for future implementation of VMS property in the default hal. For now, just
// returns OK; otherwise, hal clients crash with property not supported.
return V2_0::StatusCode::OK;
- break;
default:
- return mVehicleHal20->set(propValue);
+ return V2_0::impl::EmulatedVehicleHal::set(propValue);
}
}
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.h
new file mode 100644
index 0000000..7cc3b79
--- /dev/null
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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_automotive_vehicle_V2_1_impl_EmulatedVehicleHal_H_
+#define android_hardware_automotive_vehicle_V2_1_impl_EmulatedVehicleHal_H_
+
+#include <memory>
+
+#include <utils/SystemClock.h>
+
+#include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHal.h>
+#include <vhal_v2_0/VehiclePropertyStore.h>
+#include <vhal_v2_1/Obd2SensorStore.h>
+
+#include "DefaultConfig.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_1 {
+
+namespace impl {
+
+using namespace std::placeholders;
+
+class EmulatedVehicleHal : public V2_0::impl::EmulatedVehicleHal {
+public:
+ EmulatedVehicleHal(V2_0::VehiclePropertyStore* propStore)
+ : V2_0::impl::EmulatedVehicleHal(propStore), mPropStore(propStore) {
+ initStaticConfig();
+ }
+
+ VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue,
+ V2_0::StatusCode* outStatus) override;
+
+ V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override;
+
+ void onCreate() override;
+
+private:
+ void initStaticConfig();
+ void initObd2LiveFrame(const V2_0::VehiclePropConfig& propConfig);
+ void initObd2FreezeFrame(const V2_0::VehiclePropConfig& propConfig);
+ V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue,
+ V2_0::VehiclePropValue* outValue);
+ V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *outValue);
+ V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue);
+
+private:
+ V2_0::VehiclePropertyStore* mPropStore;
+};
+
+} // impl
+
+} // namespace V2_1
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_
diff --git a/automotive/vehicle/2.1/default/service.cpp b/automotive/vehicle/2.1/default/service.cpp
index 0844622..4873279 100644
--- a/automotive/vehicle/2.1/default/service.cpp
+++ b/automotive/vehicle/2.1/default/service.cpp
@@ -23,9 +23,10 @@
#include <android/hardware/automotive/vehicle/2.1/IVehicle.h>
#include <vhal_v2_0/VehicleHalManager.h>
-#include <vhal_v2_0/DefaultVehicleHal.h>
+#include <vhal_v2_0/VehiclePropertyStore.h>
+#include <vhal_v2_0/EmulatedVehicleHal.h>
-#include <vhal_v2_1/DefaultVehicleHal.h>
+#include <vhal_v2_1/EmulatedVehicleHal.h>
using namespace android;
using namespace android::hardware;
@@ -80,10 +81,10 @@
};
int main(int /* argc */, char* /* argv */ []) {
- auto halImpl20 = std::make_unique<V2_0::impl::DefaultVehicleHal>();
- auto halImpl21 = std::make_unique<V2_1::impl::DefaultVehicleHal>(halImpl20.get());
-
- auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(halImpl21.get());
+ auto store = std::make_unique<V2_0::VehiclePropertyStore>();
+ auto hal = std::make_unique<V2_1::impl::EmulatedVehicleHal>(store.get());
+ auto emulator = std::make_unique<V2_0::impl::VehicleEmulator>(hal.get());
+ auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(hal.get());
Vehicle_V2_1 vehicle21(vehicleManager.get());
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index 8545d2f..0f76c39 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -2,3 +2,4 @@
class hal
user bluetooth
group bluetooth
+ writepid /dev/stune/foreground/tasks
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index 8701ec1..9f4d188 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -40,6 +40,22 @@
const int kMaxCameraDeviceNameLen = 128;
const int kMaxCameraIdLen = 16;
+bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
+ std::string* cameraId) {
+ std::string deviceNameStd(deviceName.c_str());
+ std::smatch sm;
+ if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
+ if (deviceVersion != nullptr) {
+ *deviceVersion = sm[1];
+ }
+ if (cameraId != nullptr) {
+ *cameraId = sm[2];
+ }
+ return true;
+ }
+ return false;
+}
+
} // anonymous namespace
using ::android::hardware::camera::common::V1_0::CameraMetadataType;
@@ -112,30 +128,22 @@
}
}
-bool CameraProvider::matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
- std::string deviceNameStd(deviceName.c_str());
- return std::regex_match(deviceNameStd, sm, kDeviceNameRE);
-}
-
std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) {
- std::smatch sm;
- bool match = matchDeviceName(deviceName, sm);
- if (!match) {
- return std::string("");
- }
- return sm[2];
+ std::string cameraId;
+ matchDeviceName(deviceName, nullptr, &cameraId);
+ return cameraId;
}
int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) {
- std::smatch sm;
- bool match = matchDeviceName(deviceName, sm);
+ std::string deviceVersion;
+ bool match = matchDeviceName(deviceName, &deviceVersion, nullptr);
if (!match) {
return -1;
}
- if (sm[1].compare(kHAL3_2) == 0) {
+ if (deviceVersion == kHAL3_2) {
// maybe switched to 3.4 or define the hidl version enum later
return CAMERA_DEVICE_API_VERSION_3_2;
- } else if (sm[1].compare(kHAL1_0) == 0) {
+ } else if (deviceVersion == kHAL1_0) {
return CAMERA_DEVICE_API_VERSION_1_0;
}
return 0;
@@ -322,15 +330,13 @@
Return<void> CameraProvider::getCameraDeviceInterface_V1_x(
const hidl_string& cameraDeviceName, getCameraDeviceInterface_V1_x_cb _hidl_cb) {
- std::smatch sm;
- bool match = matchDeviceName(cameraDeviceName, sm);
+ std::string cameraId, deviceVersion;
+ bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
if (!match) {
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
}
- std::string cameraId = sm[2];
- std::string deviceVersion = sm[1];
std::string deviceName(cameraDeviceName.c_str());
ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
@@ -377,15 +383,13 @@
Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) {
- std::smatch sm;
- bool match = matchDeviceName(cameraDeviceName, sm);
+ std::string cameraId, deviceVersion;
+ bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
if (!match) {
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
}
- std::string cameraId = sm[2];
- std::string deviceVersion = sm[1];
std::string deviceName(cameraDeviceName.c_str());
ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
index 2a43e2f..d7b0ea6 100644
--- a/camera/provider/2.4/default/CameraProvider.h
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -91,7 +91,6 @@
bool setUpVendorTags();
// extract legacy camera ID/device version from a HIDL device name
- static bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm);
static std::string getLegacyCameraId(const hidl_string& deviceName);
static int getCameraDeviceVersion(const hidl_string& deviceName);
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.cpp b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
index 9469ab4..70bd803 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.cpp
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
@@ -12,7 +12,6 @@
Return<void> SurfaceFlingerConfigs::vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) {
#ifdef VSYNC_EVENT_PHASE_OFFSET_NS
_hidl_cb({true, VSYNC_EVENT_PHASE_OFFSET_NS});
- LOG(INFO) << "vsync event phase offset ns = " << VSYNC_EVENT_PHASE_OFFSET_NS;
#else
_hidl_cb({false, 0});
#endif
@@ -22,7 +21,6 @@
Return<void> SurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) {
#ifdef SF_VSYNC_EVENT_PHASE_OFFSET_NS
_hidl_cb({true, SF_VSYNC_EVENT_PHASE_OFFSET_NS});
- LOG(INFO) << "sfvsync event phase offset ns = " << SF_VSYNC_EVENT_PHASE_OFFSET_NS;
#else
_hidl_cb({false, 0});
#endif
@@ -32,7 +30,6 @@
Return<void> SurfaceFlingerConfigs::useContextPriority(useContextPriority_cb _hidl_cb) {
#ifdef USE_CONTEXT_PRIORITY
_hidl_cb({true, USE_CONTEXT_PRIORITY});
- LOG(INFO) << "SurfaceFlinger useContextPriority=" << USE_CONTEXT_PRIORITY;
#else
_hidl_cb({false, false});
#endif
@@ -42,7 +39,6 @@
Return<void> SurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) {
#ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS
_hidl_cb({true, NUM_FRAMEBUFFER_SURFACE_BUFFERS});
- LOG(INFO) << "SurfaceFlinger FrameBuffer max acquired buffers : " << NUM_FRAMEBUFFER_SURFACE_BUFFERS;
#else
_hidl_cb({false, 0});
#endif
@@ -55,7 +51,6 @@
value = true;
#endif
_hidl_cb({true, value});
- LOG(INFO) << "SurfaceFlinger Display: " << (value ? "Wide Color" : "Standard Color");
return Void();
}
@@ -65,7 +60,6 @@
value = false;
#endif
_hidl_cb({true, value});
- LOG(INFO) << "SurfaceFlinger hasSyncFramework: " << value;
return Void();
}
@@ -75,14 +69,12 @@
value = true;
#endif
_hidl_cb({true, value});
- LOG(INFO) << "SurfaceFlinger Display: " << (value ? "HDR" : "SDR");
return Void();
}
Return<void> SurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) {
#ifdef PRESENT_TIME_OFFSET_FROM_VSYNC_NS
_hidl_cb({true, PRESENT_TIME_OFFSET_FROM_VSYNC_NS});
- LOG(INFO) << "SurfaceFlinger presentTimeStampOffsetNs = " << PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
#else
_hidl_cb({false, 0});
#endif
@@ -95,7 +87,6 @@
value = true;
#endif
_hidl_cb({true, value});
- LOG(INFO) << "SurfaceFlinger forceHwcForRGBtoYUV: " << value;
return Void();
}
@@ -104,7 +95,6 @@
#ifdef MAX_VIRTUAL_DISPLAY_DIMENSION
maxSize = MAX_VIRTUAL_DISPLAY_DIMENSION;
_hidl_cb({true, maxSize});
- LOG(INFO) << "SurfaceFlinger MaxVirtualDisplaySize: " << maxSize;
#else
_hidl_cb({false, maxSize});
#endif
@@ -119,7 +109,6 @@
specified = true;
#endif
_hidl_cb({specified, value});
- LOG(INFO) << "SurfaceFlinger UseVrFlinger: " << (value ? "true" : "false");
return Void();
}
diff --git a/configstore/utils/Android.bp b/configstore/utils/Android.bp
index aa420d1..2c8aad6 100644
--- a/configstore/utils/Android.bp
+++ b/configstore/utils/Android.bp
@@ -14,14 +14,22 @@
// limitations under the License.
//
-cc_library_headers {
+cc_library_shared {
name: "android.hardware.configstore-utils",
defaults: ["hidl_defaults"],
+
+ srcs: [ "ConfigStoreUtils.cpp" ],
+
export_include_dirs: ["include"],
+
shared_libs: [
+ "android.hardware.configstore@1.0",
+ "libbase",
"libhidlbase"
],
export_shared_lib_headers: [
+ "android.hardware.configstore@1.0",
+ "libbase",
"libhidlbase"
],
}
diff --git a/configstore/utils/ConfigStoreUtils.cpp b/configstore/utils/ConfigStoreUtils.cpp
new file mode 100644
index 0000000..5a1fb42
--- /dev/null
+++ b/configstore/utils/ConfigStoreUtils.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "ConfigStore"
+
+#include <android-base/logging.h>
+#include <configstore/Utils.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+
+bool wouldLogInfo() {
+ return WOULD_LOG(INFO);
+}
+
+void logAlwaysInfo(const std::string& message) {
+ LOG(INFO) << message;
+}
+
+void logAlwaysError(const std::string& message) {
+ LOG(ERROR) << message;
+}
+
+} // namespace details
+} // namespace hardware
+} // namespace android
diff --git a/configstore/utils/include/configstore/Utils.h b/configstore/utils/include/configstore/Utils.h
index 46cc9b0..a54ce85 100644
--- a/configstore/utils/include/configstore/Utils.h
+++ b/configstore/utils/include/configstore/Utils.h
@@ -17,24 +17,31 @@
#ifndef ANDROID_HARDWARE_CONFIGSTORE_UTILS_H
#define ANDROID_HARDWARE_CONFIGSTORE_UTILS_H
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <hidl/Status.h>
-#include <stdatomic.h>
-#pragma push_macro("LOG_TAG")
-#undef LOG_TAG
-#define LOG_TAG "ConfigStoreUtil"
+#include <sstream>
namespace android {
namespace hardware {
+
+namespace details {
+// Templated classes can use the below method
+// to avoid creating dependencies on liblog.
+bool wouldLogInfo();
+void logAlwaysInfo(const std::string& message);
+void logAlwaysError(const std::string& message);
+} // namespace details
+
namespace configstore {
+using namespace android::hardware::configstore::V1_0;
// arguments V: type for the value (i.e., OptionalXXX)
// I: interface class name
// func: member function pointer
-using namespace V1_0;
-
template<typename V, typename I, android::hardware::Return<void> (I::* func)
(std::function<void(const V&)>)>
decltype(V::value) get(const decltype(V::value) &defValue) {
+ using namespace android::hardware::details;
auto getHelper = []()->V {
V ret;
sp<I> configs = I::getService();
@@ -47,7 +54,11 @@
ret = v;
});
if (!status.isOk()) {
- ALOGE("HIDL call failed. %s", status.description().c_str());
+ std::ostringstream oss;
+ oss << "HIDL call failed for retrieving a config item from "
+ "configstore : "
+ << status.description().c_str();
+ logAlwaysError(oss.str());
ret.specified = false;
}
}
@@ -56,6 +67,24 @@
};
static V cachedValue = getHelper();
+ if (wouldLogInfo()) {
+ std::string iname = __PRETTY_FUNCTION__;
+ // func name starts with "func = " in __PRETTY_FUNCTION__
+ auto pos = iname.find("func = ");
+ if (pos != std::string::npos) {
+ iname = iname.substr(pos + sizeof("func = "));
+ iname.pop_back(); // remove trailing ']'
+ } else {
+ iname += " (unknown)";
+ }
+
+ std::ostringstream oss;
+ oss << iname << " retrieved: "
+ << (cachedValue.specified ? cachedValue.value : defValue)
+ << (cachedValue.specified ? "" : " (default)");
+ logAlwaysInfo(oss.str());
+ }
+
return cachedValue.specified ? cachedValue.value : defValue;
}
@@ -99,6 +128,4 @@
} // namespace hardware
} // namespace android
-#pragma pop_macro("LOG_TAG")
-
#endif // ANDROID_HARDWARE_CONFIGSTORE_UTILS_H
diff --git a/drm/1.0/IDrmPlugin.hal b/drm/1.0/IDrmPlugin.hal
index 083b311..07b0832 100644
--- a/drm/1.0/IDrmPlugin.hal
+++ b/drm/1.0/IDrmPlugin.hal
@@ -179,10 +179,9 @@
* certificate authority (CA) is an entity which issues digital certificates
* for use by other parties. It is an example of a trusted third party.
* @return status the status of the call. The status must be OK or one of
- * the following errors: BAD_VALUE if the sessionId is invalid,
- * ERROR_DRM_CANNOT_HANDLE if the drm scheme does not require provisioning
- * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
- * request cannot be generated.
+ * the following errors: ERROR_DRM_CANNOT_HANDLE if the drm scheme does not
+ * require provisioning or ERROR_DRM_INVALID_STATE if the HAL is in a state
+ * where the provision request cannot be generated.
* @return request if successful the opaque certificate request blob
* is returned
* @return defaultUrl URL that the provisioning request should be
diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk
index f2334a0..23a4506 100644
--- a/drm/1.0/default/Android.mk
+++ b/drm/1.0/default/Android.mk
@@ -38,9 +38,12 @@
LOCAL_C_INCLUDES := \
hardware/interfaces/drm
-# TODO: The legacy DRM plugins only support 32-bit. They need
-# to be migrated to 64-bit (b/18948909)
+# TODO(b/18948909) Some legacy DRM plugins only support 32-bit. They need to be
+# migrated to 64-bit. Once all of a device's legacy DRM plugins support 64-bit,
+# that device can turn on ENABLE_MEDIADRM_64 to build this service as 64-bit.
+ifneq ($(ENABLE_MEDIADRM_64), true)
LOCAL_32_BIT_ONLY := true
+endif
include $(BUILD_EXECUTABLE)
@@ -55,11 +58,13 @@
DrmPlugin.cpp \
CryptoFactory.cpp \
CryptoPlugin.cpp \
+ LegacyPluginPath.cpp \
TypeConvert.cpp \
LOCAL_SHARED_LIBRARIES := \
android.hardware.drm@1.0 \
android.hidl.memory@1.0 \
+ libcutils \
libhidlbase \
libhidlmemory \
libhidltransport \
@@ -72,8 +77,11 @@
frameworks/native/include \
frameworks/av/include
-# TODO: The legacy DRM plugins only support 32-bit. They need
-# to be migrated to 64-bit (b/18948909)
+# TODO: Some legacy DRM plugins only support 32-bit. They need to be migrated to
+# 64-bit. (b/18948909) Once all of a device's legacy DRM plugins support 64-bit,
+# that device can turn on ENABLE_MEDIADRM_64 to build this impl as 64-bit.
+ifneq ($(ENABLE_MEDIADRM_64), true)
LOCAL_32_BIT_ONLY := true
+endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/1.0/default/CryptoFactory.cpp b/drm/1.0/default/CryptoFactory.cpp
index e46233d..935786d 100644
--- a/drm/1.0/default/CryptoFactory.cpp
+++ b/drm/1.0/default/CryptoFactory.cpp
@@ -17,6 +17,7 @@
#include "CryptoFactory.h"
#include "CryptoPlugin.h"
+#include "LegacyPluginPath.h"
#include "TypeConvert.h"
#include <utils/Log.h>
@@ -27,7 +28,7 @@
namespace implementation {
CryptoFactory::CryptoFactory() :
- loader("/vendor/lib/mediadrm", "createCryptoFactory") {
+ loader(getDrmPluginPath(), "createCryptoFactory") {
}
// Methods from ::android::hardware::drm::V1_0::ICryptoFactory follow.
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index 9c51b15..5e5b5a7 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -35,7 +35,7 @@
// Methods from ::android::hardware::drm::V1_0::ICryptoPlugin follow
Return<bool> CryptoPlugin::requiresSecureDecoderComponent(
const hidl_string& mime) {
- return mLegacyPlugin->requiresSecureDecoderComponent(mime);
+ return mLegacyPlugin->requiresSecureDecoderComponent(mime.c_str());
}
Return<void> CryptoPlugin::notifyResolution(uint32_t width,
diff --git a/drm/1.0/default/DrmFactory.cpp b/drm/1.0/default/DrmFactory.cpp
index 9ec0ab7..72466a1 100644
--- a/drm/1.0/default/DrmFactory.cpp
+++ b/drm/1.0/default/DrmFactory.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016 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
@@ -17,6 +17,7 @@
#include "DrmFactory.h"
#include "DrmPlugin.h"
+#include "LegacyPluginPath.h"
#include "TypeConvert.h"
#include <utils/Log.h>
@@ -27,7 +28,7 @@
namespace implementation {
DrmFactory::DrmFactory() :
- loader("/vendor/lib/mediadrm", "createDrmFactory") {
+ loader(getDrmPluginPath(), "createDrmFactory") {
}
// Methods from ::android::hardware::drm::V1_0::IDrmFactory follow.
diff --git a/drm/1.0/default/DrmPlugin.cpp b/drm/1.0/default/DrmPlugin.cpp
index c7428a5..1695ef7 100644
--- a/drm/1.0/default/DrmPlugin.cpp
+++ b/drm/1.0/default/DrmPlugin.cpp
@@ -70,15 +70,15 @@
if (status == android::OK) {
android::KeyedVector<String8, String8> legacyOptionalParameters;
for (size_t i = 0; i < optionalParameters.size(); i++) {
- legacyOptionalParameters.add(String8(optionalParameters[i].key),
- String8(optionalParameters[i].value));
+ legacyOptionalParameters.add(String8(optionalParameters[i].key.c_str()),
+ String8(optionalParameters[i].value.c_str()));
}
android::DrmPlugin::KeyRequestType legacyRequestType =
android::DrmPlugin::kKeyRequestType_Unknown;
status = mLegacyPlugin->getKeyRequest(toVector(scope),
- toVector(initData), String8(mimeType), legacyKeyType,
+ toVector(initData), String8(mimeType.c_str()), legacyKeyType,
legacyOptionalParameters, legacyRequest, defaultUrl,
&legacyRequestType);
@@ -149,7 +149,7 @@
Vector<uint8_t> legacyRequest;
String8 legacyDefaultUrl;
status_t status = mLegacyPlugin->getProvisionRequest(
- String8(certificateType), String8(certificateAuthority),
+ String8(certificateType.c_str()), String8(certificateAuthority.c_str()),
legacyRequest, legacyDefaultUrl);
_hidl_cb(toStatus(status), toHidlVec(legacyRequest),
@@ -217,7 +217,7 @@
getPropertyString_cb _hidl_cb) {
String8 legacyValue;
status_t status = mLegacyPlugin->getPropertyString(
- String8(propertyName), legacyValue);
+ String8(propertyName.c_str()), legacyValue);
_hidl_cb(toStatus(status), legacyValue.string());
return Void();
}
@@ -226,7 +226,7 @@
getPropertyByteArray_cb _hidl_cb) {
Vector<uint8_t> legacyValue;
status_t status = mLegacyPlugin->getPropertyByteArray(
- String8(propertyName), legacyValue);
+ String8(propertyName.c_str()), legacyValue);
_hidl_cb(toStatus(status), toHidlVec(legacyValue));
return Void();
}
@@ -234,15 +234,15 @@
Return<Status> DrmPlugin::setPropertyString(const hidl_string& propertyName,
const hidl_string& value) {
status_t legacyStatus =
- mLegacyPlugin->setPropertyString(String8(propertyName),
- String8(value));
+ mLegacyPlugin->setPropertyString(String8(propertyName.c_str()),
+ String8(value.c_str()));
return toStatus(legacyStatus);
}
Return<Status> DrmPlugin::setPropertyByteArray(
const hidl_string& propertyName, const hidl_vec<uint8_t>& value) {
status_t legacyStatus =
- mLegacyPlugin->setPropertyByteArray(String8(propertyName),
+ mLegacyPlugin->setPropertyByteArray(String8(propertyName.c_str()),
toVector(value));
return toStatus(legacyStatus);
}
@@ -251,7 +251,7 @@
const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
status_t legacyStatus =
mLegacyPlugin->setCipherAlgorithm(toVector(sessionId),
- String8(algorithm));
+ String8(algorithm.c_str()));
return toStatus(legacyStatus);
}
@@ -259,7 +259,7 @@
const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
status_t legacyStatus =
mLegacyPlugin->setMacAlgorithm(toVector(sessionId),
- String8(algorithm));
+ String8(algorithm.c_str()));
return toStatus(legacyStatus);
}
@@ -313,7 +313,7 @@
Vector<uint8_t> legacySignature;
status_t status = mLegacyPlugin->signRSA(toVector(sessionId),
- String8(algorithm), toVector(message), toVector(wrappedKey),
+ String8(algorithm.c_str()), toVector(message), toVector(wrappedKey),
legacySignature);
_hidl_cb(toStatus(status), toHidlVec(legacySignature));
return Void();
@@ -327,19 +327,25 @@
Return<void> DrmPlugin::sendEvent(EventType eventType,
const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
- mListener->sendEvent(eventType, sessionId, data);
+ if (mListener != nullptr) {
+ mListener->sendEvent(eventType, sessionId, data);
+ }
return Void();
}
Return<void> DrmPlugin::sendExpirationUpdate(
const hidl_vec<uint8_t>& sessionId, int64_t expiryTimeInMS) {
- mListener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ if (mListener != nullptr) {
+ mListener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ }
return Void();
}
Return<void> DrmPlugin::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
- mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ if (mListener != nullptr) {
+ mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ }
return Void();
}
diff --git a/drm/1.0/default/LegacyPluginPath.cpp b/drm/1.0/default/LegacyPluginPath.cpp
new file mode 100644
index 0000000..369059d
--- /dev/null
+++ b/drm/1.0/default/LegacyPluginPath.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LegacyPluginPath.h"
+
+#include <cutils/properties.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+const char* getDrmPluginPath() {
+ if (property_get_bool("drm.64bit.enabled", false)) {
+ return "/vendor/lib64/mediadrm";
+ } else {
+ return "/vendor/lib/mediadrm";
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/default/LegacyPluginPath.h b/drm/1.0/default/LegacyPluginPath.h
new file mode 100644
index 0000000..7145f2e
--- /dev/null
+++ b/drm/1.0/default/LegacyPluginPath.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LEGACY_PLUGIN_PATH_H_
+
+#define LEGACY_PLUGIN_PATH_H_
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+const char* getDrmPluginPath();
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // LEGACY_PLUGIN_PATH_H_
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index 36d7d1c..43ea372 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -34,6 +34,8 @@
"libhwbinder",
"liblog",
"libnativehelper",
+ "libssl",
+ "libcrypto",
"libutils",
],
static_libs: [
diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
index 2296d2d..6910855 100644
--- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
@@ -27,6 +27,7 @@
#include <hidl/HidlSupport.h>
#include <hidlmemory/mapping.h>
#include <memory>
+#include <openssl/aes.h>
#include <random>
#include "VtsHalHidlTargetTestBase.h"
@@ -125,6 +126,39 @@
}
/**
+ * Ensure the factory doesn't support an empty UUID
+ */
+TEST_F(DrmHalClearkeyFactoryTest, EmptyPluginUUIDNotSupported) {
+ hidl_array<uint8_t, 16> emptyUUID;
+ EXPECT_FALSE(drmFactory->isCryptoSchemeSupported(emptyUUID));
+ EXPECT_FALSE(cryptoFactory->isCryptoSchemeSupported(emptyUUID));
+}
+
+/**
+ * Ensure empty content type is not supported
+ */
+TEST_F(DrmHalClearkeyFactoryTest, EmptyContentTypeNotSupported) {
+ hidl_string empty;
+ EXPECT_FALSE(drmFactory->isContentTypeSupported(empty));
+}
+
+/**
+ * Ensure invalid content type is not supported
+ */
+TEST_F(DrmHalClearkeyFactoryTest, InvalidContentTypeNotSupported) {
+ hidl_string invalid("abcdabcd");
+ EXPECT_FALSE(drmFactory->isContentTypeSupported(invalid));
+}
+
+/**
+ * Ensure valid content type is supported
+ */
+TEST_F(DrmHalClearkeyFactoryTest, ValidContentTypeSupported) {
+ hidl_string cencType("cenc");
+ EXPECT_TRUE(drmFactory->isContentTypeSupported(cencType));
+}
+
+/**
* Ensure clearkey drm plugin can be created
*/
TEST_F(DrmHalClearkeyFactoryTest, CreateClearKeyDrmPlugin) {
@@ -418,6 +452,26 @@
}
/**
+ * Test that a removeKeys on an empty sessionID returns BAD_VALUE
+ */
+TEST_F(DrmHalClearkeyPluginTest, RemoveKeysEmptySessionId) {
+ SessionId sessionId;
+ Status status = drmPlugin->removeKeys(sessionId);
+ EXPECT_TRUE(status == Status::BAD_VALUE);
+}
+
+/**
+ * Remove keys is not supported for clearkey.
+ */
+TEST_F(DrmHalClearkeyPluginTest, RemoveKeysNewSession) {
+ SessionId sessionId = openSession();
+ Status status = drmPlugin->removeKeys(sessionId);
+ // Clearkey plugin doesn't support remove keys
+ EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
+ closeSession(sessionId);
+}
+
+/**
* Test that the clearkey plugin doesn't support getting
* secure stops.
*/
@@ -617,7 +671,7 @@
;
hidl_vec<uint8_t> keyId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
hidl_vec<uint8_t> input = {1, 2, 3, 4, 5};
- hidl_vec<uint8_t> iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ hidl_vec<uint8_t> iv = std::vector<uint8_t>(AES_BLOCK_SIZE, 0);
auto res = drmPlugin->encrypt(session, keyId, input, iv,
[&](Status status, const hidl_vec<uint8_t>&) {
EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE,
@@ -629,10 +683,9 @@
TEST_F(DrmHalClearkeyPluginTest, GenericDecryptNotSupported) {
SessionId session = openSession();
- ;
hidl_vec<uint8_t> keyId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
hidl_vec<uint8_t> input = {1, 2, 3, 4, 5};
- hidl_vec<uint8_t> iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ hidl_vec<uint8_t> iv = std::vector<uint8_t>(AES_BLOCK_SIZE, 0);
auto res = drmPlugin->decrypt(session, keyId, input, iv,
[&](Status status, const hidl_vec<uint8_t>&) {
EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE,
@@ -763,6 +816,17 @@
}
/**
+ * setMediaDrmSession with an empty session id: BAD_VALUE. An
+ * empty session clears the previously set session and should
+ * return OK.
+ */
+TEST_F(DrmHalClearkeyPluginTest, SetMediaDrmSessionEmptySession) {
+ SessionId sessionId;
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+}
+
+/**
* Decrypt tests
*/
@@ -771,9 +835,15 @@
void loadKeys(const SessionId& sessionId);
void fillRandom(const sp<IMemory>& memory);
hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
- EXPECT_EQ(vec.size(), 16u);
+ EXPECT_EQ(16u, vec.size());
return hidl_array<uint8_t, 16>(&vec[0]);
}
+ uint32_t decrypt(Mode mode, uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const Pattern& pattern, Status status);
+ void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+ void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
};
/**
@@ -847,36 +917,162 @@
}
}
-/**
- * Positive decrypt test. "Decrypt" a single clear
- * segment. Verify data matches.
- */
-TEST_F(DrmHalClearkeyDecryptTest, ClearSegmentTest) {
- const size_t kSegmentSize = 1024;
+uint32_t DrmHalClearkeyDecryptTest::decrypt(Mode mode,
+ uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const Pattern& pattern, Status expectedStatus) {
const size_t kSegmentIndex = 0;
const vector<uint8_t> keyId = {0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47,
0x7e, 0x87, 0x7e, 0x57, 0xd0, 0x0d,
0x1e, 0xd0, 0x0d, 0x1e};
- uint8_t iv[16] = {0};
+ const vector<uint8_t> contentKey = {0x1a, 0x8a, 0x20, 0x95, 0xe4,
+ 0xde, 0xb2, 0xd2, 0x9e, 0xc8,
+ 0x16, 0xac, 0x7b, 0xae, 0x20, 0x82};
+ uint8_t localIv[AES_BLOCK_SIZE];
+ memcpy(localIv, iv, AES_BLOCK_SIZE);
+ size_t totalSize = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ totalSize += subSamples[i].numBytesOfClearData;
+ totalSize += subSamples[i].numBytesOfEncryptedData;
+ }
+
+ // The first totalSize bytes of shared memory is the encrypted
+ // input, the second totalSize bytes is the decrypted output.
sp<IMemory> sharedMemory =
- getDecryptMemory(kSegmentSize * 2, kSegmentIndex);
+ getDecryptMemory(totalSize * 2, kSegmentIndex);
- SharedBuffer sourceBuffer = {
- .bufferId = kSegmentIndex, .offset = 0, .size = kSegmentSize};
+ const SharedBuffer sourceBuffer = {
+ .bufferId = kSegmentIndex, .offset = 0, .size = totalSize};
fillRandom(sharedMemory);
- DestinationBuffer destBuffer = {.type = BufferType::SHARED_MEMORY,
- {.bufferId = kSegmentIndex,
- .offset = kSegmentSize,
- .size = kSegmentSize},
- .secureMemory = nullptr};
+ const DestinationBuffer destBuffer = {.type = BufferType::SHARED_MEMORY,
+ {.bufferId = kSegmentIndex,
+ .offset = totalSize,
+ .size = totalSize},
+ .secureMemory = nullptr};
+ const uint64_t offset = 0;
+ const bool kNotSecure = false;
+ uint32_t bytesWritten = 0;
+ auto res = cryptoPlugin->decrypt(kNotSecure, toHidlArray(keyId), localIv, mode,
+ pattern, subSamples, sourceBuffer, offset, destBuffer,
+ [&](Status status, uint32_t count, string detailedError) {
+ EXPECT_EQ(expectedStatus, status) << "Unexpected decrypt status " <<
+ detailedError;
+ bytesWritten = count;
+ });
+ EXPECT_OK(res);
- Pattern noPattern = {0, 0};
- vector<SubSample> subSamples = {{.numBytesOfClearData = kSegmentSize,
- .numBytesOfEncryptedData = 0}};
- uint64_t offset = 0;
+ if (bytesWritten != totalSize) {
+ return bytesWritten;
+ }
+ uint8_t* base = static_cast<uint8_t*>(
+ static_cast<void*>(sharedMemory->getPointer()));
+ // generate reference vector
+ vector<uint8_t> reference(totalSize);
+
+ memcpy(localIv, iv, AES_BLOCK_SIZE);
+ switch (mode) {
+ case Mode::UNENCRYPTED:
+ memcpy(&reference[0], base, totalSize);
+ break;
+ case Mode::AES_CTR:
+ aes_ctr_decrypt(&reference[0], base, localIv, subSamples, contentKey);
+ break;
+ case Mode::AES_CBC:
+ aes_cbc_decrypt(&reference[0], base, localIv, subSamples, contentKey);
+ break;
+ case Mode::AES_CBC_CTS:
+ EXPECT_TRUE(false) << "AES_CBC_CTS mode not supported";
+ break;
+ }
+
+ // compare reference to decrypted data which is at base + total size
+ EXPECT_EQ(0, memcmp(static_cast<void *>(&reference[0]),
+ static_cast<void*>(base + totalSize), totalSize))
+ << "decrypt data mismatch";
+ return totalSize;
+}
+
+/**
+ * Decrypt a list of clear+encrypted subsamples using the specified key
+ * in AES-CTR mode
+ */
+void DrmHalClearkeyDecryptTest::aes_ctr_decrypt(uint8_t* dest, uint8_t* src,
+ uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const vector<uint8_t>& key) {
+ AES_KEY decryptionKey;
+ AES_set_encrypt_key(&key[0], 128, &decryptionKey);
+
+ size_t offset = 0;
+ unsigned int blockOffset = 0;
+ uint8_t previousEncryptedCounter[AES_BLOCK_SIZE];
+ memset(previousEncryptedCounter, 0, AES_BLOCK_SIZE);
+
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ const SubSample& subSample = subSamples[i];
+
+ if (subSample.numBytesOfClearData > 0) {
+ memcpy(dest + offset, src + offset, subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
+ }
+
+ if (subSample.numBytesOfEncryptedData > 0) {
+ AES_ctr128_encrypt(src + offset, dest + offset,
+ subSample.numBytesOfEncryptedData, &decryptionKey,
+ iv, previousEncryptedCounter, &blockOffset);
+ offset += subSample.numBytesOfEncryptedData;
+ }
+ }
+}
+
+/**
+ * Decrypt a list of clear+encrypted subsamples using the specified key
+ * in AES-CBC mode
+ */
+void DrmHalClearkeyDecryptTest::aes_cbc_decrypt(uint8_t* dest, uint8_t* src,
+ uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const vector<uint8_t>& key) {
+ AES_KEY decryptionKey;
+ AES_set_encrypt_key(&key[0], 128, &decryptionKey);
+
+ size_t offset = 0;
+ size_t num = 0;
+ size_t ecount_buf = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ memcpy(dest + offset, src + offset, subSamples[i].numBytesOfClearData);
+ offset += subSamples[i].numBytesOfClearData;
+
+ AES_cbc_encrypt(src + offset, dest + offset, subSamples[i].numBytesOfEncryptedData,
+ &decryptionKey, iv, 0 /* decrypt */);
+ offset += subSamples[i].numBytesOfEncryptedData;
+ }
+}
+
+/**
+ * Test query key status
+ */
+TEST_F(DrmHalClearkeyDecryptTest, TestQueryKeyStatus) {
+ auto sessionId = openSession();
+ auto res = drmPlugin->queryKeyStatus(sessionId,
+ [&](Status status, KeyedVector /* info */) {
+ // clearkey doesn't support this method
+ EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
+ });
+ EXPECT_OK(res);
+}
+
+
+/**
+ * Positive decrypt test. "Decrypt" a single clear segment
+ */
+TEST_F(DrmHalClearkeyDecryptTest, ClearSegmentTest) {
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const uint32_t kByteCount = 256;
+ const vector<SubSample> subSamples = {
+ {.numBytesOfClearData = kByteCount,
+ .numBytesOfEncryptedData = 0}};
auto sessionId = openSession();
loadKeys(sessionId);
@@ -884,21 +1080,57 @@
EXPECT_EQ(Status::OK, status);
const bool kNotSecure = false;
- auto res = cryptoPlugin->decrypt(
- kNotSecure, toHidlArray(keyId), iv, Mode::UNENCRYPTED, noPattern,
- subSamples, sourceBuffer, offset, destBuffer,
- [&](Status status, uint32_t bytesWritten, string detailedError) {
- EXPECT_EQ(Status::OK, status) << "Failure in decryption:"
- << detailedError;
- EXPECT_EQ(bytesWritten, kSegmentSize);
- });
- EXPECT_OK(res);
+ uint32_t byteCount = decrypt(Mode::UNENCRYPTED, &iv[0], subSamples,
+ noPattern, Status::OK);
+ EXPECT_EQ(kByteCount, byteCount);
- uint8_t* base = static_cast<uint8_t*>(
- static_cast<void*>(sharedMemory->getPointer()));
+ closeSession(sessionId);
+}
- EXPECT_EQ(0, memcmp(static_cast<void*>(base),
- static_cast<void*>(base + kSegmentSize), kSegmentSize))
- << "decrypt data mismatch";
+/**
+ * Positive decrypt test. Decrypt a single segment using AES_CTR.
+ * Verify data matches.
+ */
+TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTest) {
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const uint32_t kClearBytes = 512;
+ const uint32_t kEncryptedBytes = 512;
+ const vector<SubSample> subSamples = {
+ {.numBytesOfClearData = kClearBytes,
+ .numBytesOfEncryptedData = kEncryptedBytes
+ }};
+ auto sessionId = openSession();
+ loadKeys(sessionId);
+
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+
+ const bool kNotSecure = false;
+ uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples,
+ noPattern, Status::OK);
+ EXPECT_EQ(kClearBytes + kEncryptedBytes, byteCount);
+
+ closeSession(sessionId);
+}
+/**
+ * Negative decrypt test. Decrypt without loading keys.
+ */
+TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTestNoKeys) {
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const vector<SubSample> subSamples = {
+ {.numBytesOfClearData = 256,
+ .numBytesOfEncryptedData = 256}};
+ auto sessionId = openSession();
+
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+
+ const bool kNotSecure = false;
+ uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples,
+ noPattern, Status::ERROR_DRM_NO_LICENSE);
+ EXPECT_EQ(0u, byteCount);
+
closeSession(sessionId);
}
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
index db19719..73e0cfe 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
+++ b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
@@ -73,21 +73,21 @@
* value with initial version 1. The API version indicates which subclass
* version DrmHalVTSVendorModule this instance is.
*/
- virtual uint32_t getAPIVersion() = 0;
+ virtual uint32_t getAPIVersion() const = 0;
/**
* Return the UUID for the DRM HAL implementation. Protection System
* Specific
* UUID (see http://dashif.org/identifiers/protection/)
*/
- virtual std::vector<uint8_t> getUUID() = 0;
+ virtual std::vector<uint8_t> getUUID() const = 0;
/**
* Return the service name for the DRM HAL implementation. If the hal is a
* legacy
* drm plugin, i.e. not running as a HIDL service, return the empty string.
*/
- virtual std::string getServiceName() = 0;
+ virtual std::string getServiceName() const = 0;
private:
DrmHalVTSVendorModule(const DrmHalVTSVendorModule&) = delete;
@@ -103,7 +103,7 @@
DrmHalVTSVendorModule_V1() {}
virtual ~DrmHalVTSVendorModule_V1() {}
- virtual uint32_t getAPIVersion() { return 1; }
+ virtual uint32_t getAPIVersion() const { return 1; }
/**
* Handle a provisioning request. This function will be called if the HAL
@@ -178,11 +178,10 @@
const std::vector<uint8_t> keyId;
/**
- * The key value is provided to generate expected values for
- * validating
- * decryption. If isSecure is false, no key value is required.
+ * The clear content key is provided to generate expected values for
+ * validating decryption.
*/
- const std::vector<uint8_t> keyValue;
+ const std::vector<uint8_t> clearContentKey;
};
std::vector<Key> keys;
};
@@ -191,7 +190,8 @@
* Return a list of content configurations that can be exercised by the
* VTS test.
*/
- virtual std::vector<ContentConfiguration> getContentConfigurations() = 0;
+ virtual std::vector<ContentConfiguration>
+ getContentConfigurations() const = 0;
/**
* Handle a key request. This function will be called if the HAL
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
index dcfee4e..7448c42 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
@@ -21,27 +21,33 @@
#include <android/hardware/drm/1.0/ICryptoPlugin.h>
#include <android/hardware/drm/1.0/IDrmFactory.h>
#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPluginListener.h>
#include <android/hardware/drm/1.0/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <gtest/gtest.h>
#include <hidlmemory/mapping.h>
#include <memory>
+#include <openssl/aes.h>
#include <random>
-#include "VtsHalHidlTargetTestBase.h"
#include "drm_hal_vendor_module_api.h"
#include "vendor_modules.h"
+#include "VtsHalHidlTargetTestBase.h"
using ::android::hardware::drm::V1_0::BufferType;
using ::android::hardware::drm::V1_0::DestinationBuffer;
+using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_0::ICryptoFactory;
using ::android::hardware::drm::V1_0::ICryptoPlugin;
using ::android::hardware::drm::V1_0::IDrmFactory;
using ::android::hardware::drm::V1_0::IDrmPlugin;
+using ::android::hardware::drm::V1_0::IDrmPluginListener;
using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyValue;
using ::android::hardware::drm::V1_0::KeyRequestType;
+using ::android::hardware::drm::V1_0::KeyStatus;
+using ::android::hardware::drm::V1_0::KeyStatusType;
using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::KeyValue;
using ::android::hardware::drm::V1_0::Mode;
using ::android::hardware::drm::V1_0::Pattern;
using ::android::hardware::drm::V1_0::SecureStop;
@@ -56,6 +62,7 @@
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
+using ::android::hardware::Void;
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::sp;
@@ -67,6 +74,9 @@
using std::mt19937;
using std::vector;
+using ContentConfiguration = ::DrmHalVTSVendorModule_V1::ContentConfiguration;
+using Key = ::DrmHalVTSVendorModule_V1::ContentConfiguration::Key;
+
#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
@@ -80,10 +90,9 @@
class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> {
public:
DrmHalVendorFactoryTest()
- : vendorModule(gVendorModules ? static_cast<DrmHalVTSVendorModule_V1*>(
- gVendorModules->getVendorModule(
- GetParam()))
- : nullptr) {}
+ : vendorModule(static_cast<DrmHalVTSVendorModule_V1*>(
+ gVendorModules->getModule(GetParam()))),
+ contentConfigurations(vendorModule->getContentConfigurations()) {}
virtual ~DrmHalVendorFactoryTest() {}
@@ -117,14 +126,27 @@
sp<IDrmFactory> drmFactory;
sp<ICryptoFactory> cryptoFactory;
unique_ptr<DrmHalVTSVendorModule_V1> vendorModule;
+ const vector<ContentConfiguration> contentConfigurations;
};
-/**
- * Ensure the factory supports its scheme UUID
- */
-TEST_P(DrmHalVendorFactoryTest, VendorPluginSupported) {
- EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getVendorUUID()));
- EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getVendorUUID()));
+TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) {
+ const char* kVendorStr = "Vendor module ";
+ for (auto config : contentConfigurations) {
+ ASSERT_TRUE(config.name.size() > 0) << kVendorStr << "has no name";
+ ASSERT_TRUE(config.serverUrl.size() > 0) << kVendorStr
+ << "has no serverUrl";
+ ASSERT_TRUE(config.initData.size() > 0) << kVendorStr
+ << "has no init data";
+ ASSERT_TRUE(config.mimeType.size() > 0) << kVendorStr
+ << "has no mime type";
+ ASSERT_TRUE(config.keys.size() >= 1) << kVendorStr << "has no keys";
+ for (auto key : config.keys) {
+ ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr
+ << " has zero length keyId";
+ ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr
+ << " has zero length key value";
+ }
+ }
}
/**
@@ -136,6 +158,48 @@
}
/**
+ * Ensure the factory doesn't support an empty UUID
+ */
+TEST_P(DrmHalVendorFactoryTest, EmptyPluginUUIDNotSupported) {
+ hidl_array<uint8_t, 16> emptyUUID;
+ EXPECT_FALSE(drmFactory->isCryptoSchemeSupported(emptyUUID));
+ EXPECT_FALSE(cryptoFactory->isCryptoSchemeSupported(emptyUUID));
+}
+
+/**
+ * Ensure the factory supports the scheme uuid in the config
+ */
+TEST_P(DrmHalVendorFactoryTest, EmptyPluginConfigUUIDSupported) {
+ EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getVendorUUID()));
+ EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getVendorUUID()));
+}
+
+/**
+ * Ensure empty content type is not supported
+ */
+TEST_P(DrmHalVendorFactoryTest, EmptyContentTypeNotSupported) {
+ hidl_string empty;
+ EXPECT_FALSE(drmFactory->isContentTypeSupported(empty));
+}
+
+/**
+ * Ensure invalid content type is not supported
+ */
+TEST_P(DrmHalVendorFactoryTest, InvalidContentTypeNotSupported) {
+ hidl_string invalid("abcdabcd");
+ EXPECT_FALSE(drmFactory->isContentTypeSupported(invalid));
+}
+
+/**
+ * Ensure valid content types in the configs are supported
+ */
+TEST_P(DrmHalVendorFactoryTest, ValidContentTypeSupported) {
+ for (auto config : contentConfigurations) {
+ EXPECT_TRUE(drmFactory->isContentTypeSupported(config.mimeType));
+ }
+}
+
+/**
* Ensure vendor drm plugin can be created
*/
TEST_P(DrmHalVendorFactoryTest, CreateVendorDrmPlugin) {
@@ -393,6 +457,26 @@
}
/**
+ * Test that a removeKeys on an empty sessionID returns BAD_VALUE
+ */
+TEST_P(DrmHalVendorPluginTest, RemoveKeysEmptySessionId) {
+ SessionId sessionId;
+ Status status = drmPlugin->removeKeys(sessionId);
+ EXPECT_TRUE(status == Status::BAD_VALUE);
+}
+
+/**
+ * Test that remove keys returns okay on an initialized session
+ * that has no keys.
+ */
+TEST_P(DrmHalVendorPluginTest, RemoveKeysNewSession) {
+ SessionId sessionId = openSession();
+ Status status = drmPlugin->removeKeys(sessionId);
+ EXPECT_TRUE(status == Status::OK);
+ closeSession(sessionId);
+}
+
+/**
* Test that the plugin either doesn't support getting
* secure stops, or has no secure stops available after
* clearing them.
@@ -722,6 +806,175 @@
}
/**
+ * Verify that requiresSecureDecoderComponent returns true for secure
+ * configurations
+ */
+TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderConfig) {
+ const char* kVendorStr = "Vendor module ";
+ for (auto config : contentConfigurations) {
+ for (auto key : config.keys) {
+ if (key.isSecure) {
+ EXPECT_TRUE(cryptoPlugin->requiresSecureDecoderComponent(config.mimeType));
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Event Handling tests
+ */
+
+class TestDrmPluginListener : public IDrmPluginListener {
+public:
+ TestDrmPluginListener() {reset();}
+ virtual ~TestDrmPluginListener() {}
+
+ virtual Return<void> sendEvent(EventType eventType, const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& data) override {
+ eventType_ = eventType;
+ sessionId_ = sessionId;
+ data_ = data;
+ gotEvent_ = true;
+ return Void();
+ }
+
+ virtual Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) override {
+ sessionId_ = sessionId;
+ expiryTimeInMS_ = expiryTimeInMS;
+ gotExpirationUpdate_ = true;
+ return Void();
+ }
+
+ virtual Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) override {
+ sessionId_ = sessionId;
+ keyStatusList_ = keyStatusList;
+ hasNewUsableKey_ = hasNewUsableKey;
+ gotKeysChange_ = true;
+ return Void();
+ }
+
+ EventType getEventType() const {return eventType_;}
+ SessionId getSessionId() const {return sessionId_;}
+ vector<uint8_t> getData() const {return data_;}
+ int64_t getExpiryTimeInMS() const {return expiryTimeInMS_;}
+ hidl_vec<KeyStatus> getKeyStatusList() const {return keyStatusList_;}
+ bool hasNewUsableKey() {return hasNewUsableKey_;}
+ bool gotEvent() {return gotEvent_;}
+ bool gotExpirationUpdate() {return gotExpirationUpdate_;}
+ bool gotKeysChange() {return gotKeysChange_;}
+
+ void reset() {
+ gotEvent_ = gotExpirationUpdate_ = gotKeysChange_ = false;
+ eventType_ = EventType::PROVISION_REQUIRED;
+ sessionId_ = SessionId();
+ data_ = hidl_vec<uint8_t>();
+ expiryTimeInMS_ = 0;
+ keyStatusList_ = hidl_vec<KeyStatus>();
+ hasNewUsableKey_ = false;
+ }
+
+private:
+ bool gotEvent_;
+ bool gotExpirationUpdate_;
+ bool gotKeysChange_;
+
+ EventType eventType_;
+ SessionId sessionId_;
+ hidl_vec<uint8_t> data_;
+ int64_t expiryTimeInMS_;
+ hidl_vec<KeyStatus> keyStatusList_;
+ bool hasNewUsableKey_;
+};
+
+/**
+ * Simulate the plugin sending events. Make sure the listener
+ * gets them.
+ */
+TEST_P(DrmHalVendorPluginTest, ListenerEvents) {
+ sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
+ drmPlugin->setListener(listener);
+ auto sessionId = openSession();
+ vector<uint8_t> data = {0, 1, 2};
+ EventType eventTypes[] = {EventType::PROVISION_REQUIRED,
+ EventType::KEY_NEEDED,
+ EventType::KEY_EXPIRED,
+ EventType::VENDOR_DEFINED,
+ EventType::SESSION_RECLAIMED};
+ for (auto eventType : eventTypes) {
+ listener->reset();
+ drmPlugin->sendEvent(eventType, sessionId, data);
+ while (!listener->gotEvent()) {usleep(100);}
+ EXPECT_EQ(eventType, listener->getEventType());
+ EXPECT_EQ(sessionId, listener->getSessionId());
+ EXPECT_EQ(data, listener->getData());
+ }
+ closeSession(sessionId);
+}
+
+/**
+ * Simulate the plugin sending expiration updates and make sure
+ * the listener gets them.
+ */
+TEST_P(DrmHalVendorPluginTest, ListenerExpirationUpdate) {
+ sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
+ drmPlugin->setListener(listener);
+ auto sessionId = openSession();
+ drmPlugin->sendExpirationUpdate(sessionId, 100);
+ while (!listener->gotExpirationUpdate()) {usleep(100);}
+ EXPECT_EQ(sessionId, listener->getSessionId());
+ EXPECT_EQ(100, listener->getExpiryTimeInMS());
+ closeSession(sessionId);
+}
+
+/**
+ * Simulate the plugin sending keys change and make sure
+ * the listener gets them.
+ */
+TEST_P(DrmHalVendorPluginTest, ListenerKeysChange) {
+ sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
+ drmPlugin->setListener(listener);
+ auto sessionId = openSession();
+ const hidl_vec<KeyStatus> keyStatusList = {
+ {{1}, KeyStatusType::USABLE},
+ {{2}, KeyStatusType::EXPIRED},
+ {{3}, KeyStatusType::OUTPUTNOTALLOWED},
+ {{4}, KeyStatusType::STATUSPENDING},
+ {{5}, KeyStatusType::INTERNALERROR},
+ };
+
+ drmPlugin->sendKeysChange(sessionId, keyStatusList, true);
+ while (!listener->gotKeysChange()) {usleep(100);}
+ EXPECT_EQ(sessionId, listener->getSessionId());
+ EXPECT_EQ(keyStatusList, listener->getKeyStatusList());
+ EXPECT_EQ(true, listener->hasNewUsableKey());
+}
+
+/**
+ * Negative listener tests. Call send methods with no
+ * listener set.
+ */
+TEST_P(DrmHalVendorPluginTest, NotListening) {
+ sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
+ drmPlugin->setListener(listener);
+ drmPlugin->setListener(nullptr);
+
+ SessionId sessionId;
+ vector<uint8_t> data;
+ hidl_vec<KeyStatus> keyStatusList;
+ drmPlugin->sendEvent(EventType::PROVISION_REQUIRED, sessionId, data);
+ drmPlugin->sendExpirationUpdate(sessionId, 100);
+ drmPlugin->sendKeysChange(sessionId, keyStatusList, true);
+ usleep(1000); // can't wait for the event to be recieved, just wait a long time
+ EXPECT_EQ(false, listener->gotEvent());
+ EXPECT_EQ(false, listener->gotExpirationUpdate());
+ EXPECT_EQ(false, listener->gotKeysChange());
+}
+
+
+/**
* CryptoPlugin tests
*/
@@ -786,6 +1039,15 @@
}
/**
+ * setMediaDrmSession with a empty session id: BAD_VALUE
+ */
+TEST_P(DrmHalVendorPluginTest, SetMediaDrmSessionEmptySession) {
+ SessionId sessionId;
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::BAD_VALUE, status);
+}
+
+/**
* Decrypt tests
*/
@@ -796,14 +1058,23 @@
protected:
void loadKeys(const SessionId& sessionId,
- const DrmHalVTSVendorModule_V1::ContentConfiguration&
- configuration);
+ const ContentConfiguration& configuration);
void fillRandom(const sp<IMemory>& memory);
KeyedVector toHidlKeyedVector(const map<string, string>& params);
hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
EXPECT_EQ(vec.size(), 16u);
return hidl_array<uint8_t, 16>(&vec[0]);
}
+ hidl_vec<KeyValue> queryKeyStatus(SessionId sessionId);
+ void removeKeys(SessionId sessionId);
+ uint32_t decrypt(Mode mode, bool isSecure,
+ const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
+ const vector<uint8_t>& key, Status expectedStatus);
+ void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+ void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
};
KeyedVector DrmHalVendorDecryptTest::toHidlKeyedVector(
@@ -823,9 +1094,8 @@
* These tests use predetermined key request/response to
* avoid requiring a round trip to a license server.
*/
-void DrmHalVendorDecryptTest::loadKeys(
- const SessionId& sessionId,
- const DrmHalVTSVendorModule_V1::ContentConfiguration& configuration) {
+void DrmHalVendorDecryptTest::loadKeys(const SessionId& sessionId,
+ const ContentConfiguration& configuration) {
hidl_vec<uint8_t> keyRequest;
auto res = drmPlugin->getKeyRequest(
sessionId, configuration.initData, configuration.mimeType,
@@ -874,107 +1144,326 @@
}
}
-TEST_P(DrmHalVendorDecryptTest, ValidateConfigurations) {
- vector<DrmHalVTSVendorModule_V1::ContentConfiguration> configurations =
- vendorModule->getContentConfigurations();
- const char* kVendorStr = "Vendor module ";
- for (auto config : configurations) {
- ASSERT_TRUE(config.name.size() > 0) << kVendorStr << "has no name";
- ASSERT_TRUE(config.serverUrl.size() > 0) << kVendorStr
- << "has no serverUrl";
- ASSERT_TRUE(config.initData.size() > 0) << kVendorStr
- << "has no init data";
- ASSERT_TRUE(config.mimeType.size() > 0) << kVendorStr
- << "has no mime type";
- ASSERT_TRUE(config.keys.size() >= 1) << kVendorStr << "has no keys";
- for (auto key : config.keys) {
- ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr
- << " has zero length keyId";
- ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr
- << " has zero length key value";
+hidl_vec<KeyValue> DrmHalVendorDecryptTest::queryKeyStatus(SessionId sessionId) {
+ hidl_vec<KeyValue> keyStatus;
+ auto res = drmPlugin->queryKeyStatus(sessionId,
+ [&](Status status, KeyedVector info) {
+ EXPECT_EQ(Status::OK, status);
+ keyStatus = info;
+ });
+ EXPECT_OK(res);
+ return keyStatus;
+}
+
+void DrmHalVendorDecryptTest::removeKeys(SessionId sessionId) {
+ auto res = drmPlugin->removeKeys(sessionId);
+ EXPECT_OK(res);
+}
+
+uint32_t DrmHalVendorDecryptTest::decrypt(Mode mode, bool isSecure,
+ const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
+ const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
+ const vector<uint8_t>& key, Status expectedStatus) {
+ const size_t kSegmentIndex = 0;
+
+ uint8_t localIv[AES_BLOCK_SIZE];
+ memcpy(localIv, iv, AES_BLOCK_SIZE);
+
+ size_t totalSize = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ totalSize += subSamples[i].numBytesOfClearData;
+ totalSize += subSamples[i].numBytesOfEncryptedData;
+ }
+
+ // The first totalSize bytes of shared memory is the encrypted
+ // input, the second totalSize bytes is the decrypted output.
+ sp<IMemory> sharedMemory =
+ getDecryptMemory(totalSize * 2, kSegmentIndex);
+
+ SharedBuffer sourceBuffer = {
+ .bufferId = kSegmentIndex, .offset = 0, .size = totalSize};
+ fillRandom(sharedMemory);
+
+ DestinationBuffer destBuffer = {.type = BufferType::SHARED_MEMORY,
+ {.bufferId = kSegmentIndex,
+ .offset = totalSize,
+ .size = totalSize},
+ .secureMemory = nullptr};
+ uint64_t offset = 0;
+ uint32_t bytesWritten = 0;
+ auto res = cryptoPlugin->decrypt(isSecure, keyId, localIv, mode, pattern,
+ subSamples, sourceBuffer, offset, destBuffer,
+ [&](Status status, uint32_t count, string detailedError) {
+ EXPECT_EQ(expectedStatus, status) << "Unexpected decrypt status " <<
+ detailedError;
+ bytesWritten = count;
+ });
+ EXPECT_OK(res);
+
+ if (bytesWritten != totalSize) {
+ return bytesWritten;
+ }
+ uint8_t* base = static_cast<uint8_t*>(
+ static_cast<void*>(sharedMemory->getPointer()));
+
+ // generate reference vector
+ vector<uint8_t> reference(totalSize);
+
+ memcpy(localIv, iv, AES_BLOCK_SIZE);
+ switch (mode) {
+ case Mode::UNENCRYPTED:
+ memcpy(&reference[0], base, totalSize);
+ break;
+ case Mode::AES_CTR:
+ aes_ctr_decrypt(&reference[0], base, localIv, subSamples, key);
+ break;
+ case Mode::AES_CBC:
+ aes_cbc_decrypt(&reference[0], base, localIv, subSamples, key);
+ break;
+ case Mode::AES_CBC_CTS:
+ EXPECT_TRUE(false) << "AES_CBC_CTS mode not supported";
+ break;
+ }
+
+ // compare reference to decrypted data which is at base + total size
+ EXPECT_EQ(0, memcmp(static_cast<void*>(&reference[0]),
+ static_cast<void*>(base + totalSize), totalSize))
+ << "decrypt data mismatch";
+ return totalSize;
+}
+
+/**
+ * Decrypt a list of clear+encrypted subsamples using the specified key
+ * in AES-CTR mode
+ */
+void DrmHalVendorDecryptTest::aes_ctr_decrypt(uint8_t* dest, uint8_t* src,
+ uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const vector<uint8_t>& key) {
+
+ AES_KEY decryptionKey;
+ AES_set_encrypt_key(&key[0], 128, &decryptionKey);
+
+ size_t offset = 0;
+ unsigned blockOffset = 0;
+ uint8_t previousEncryptedCounter[AES_BLOCK_SIZE];
+ memset(previousEncryptedCounter, 0, AES_BLOCK_SIZE);
+
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ const SubSample& subSample = subSamples[i];
+
+ if (subSample.numBytesOfClearData > 0) {
+ memcpy(dest + offset, src + offset, subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
+ }
+
+ if (subSample.numBytesOfEncryptedData > 0) {
+ AES_ctr128_encrypt(src + offset, dest + offset,
+ subSample.numBytesOfEncryptedData, &decryptionKey,
+ iv, previousEncryptedCounter, &blockOffset);
+ offset += subSample.numBytesOfEncryptedData;
}
}
}
/**
- * Positive decrypt test. "Decrypt" a single clear
- * segment. Verify data matches.
+ * Decrypt a list of clear+encrypted subsamples using the specified key
+ * in AES-CBC mode
*/
-TEST_P(DrmHalVendorDecryptTest, ClearSegmentTest) {
- vector<DrmHalVTSVendorModule_V1::ContentConfiguration> configurations =
- vendorModule->getContentConfigurations();
- for (auto config : configurations) {
- const size_t kSegmentSize = 1024;
- const size_t kSegmentIndex = 0;
- uint8_t iv[16] = {0};
+void DrmHalVendorDecryptTest::aes_cbc_decrypt(uint8_t* dest, uint8_t* src,
+ uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+ const vector<uint8_t>& key) {
+ AES_KEY decryptionKey;
+ AES_set_encrypt_key(&key[0], 128, &decryptionKey);
- sp<IMemory> sharedMemory =
- getDecryptMemory(kSegmentSize * 2, kSegmentIndex);
+ size_t offset = 0;
+ size_t num = 0;
+ size_t ecount_buf = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ const SubSample& subSample = subSamples[i];
- SharedBuffer sourceBuffer = {
- .bufferId = kSegmentIndex, .offset = 0, .size = kSegmentSize};
- fillRandom(sharedMemory);
+ memcpy(dest + offset, src + offset, subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
- DestinationBuffer destBuffer = {.type = BufferType::SHARED_MEMORY,
- {.bufferId = kSegmentIndex,
- .offset = kSegmentSize,
- .size = kSegmentSize},
- .secureMemory = nullptr};
+ AES_cbc_encrypt(src + offset, dest + offset, subSample.numBytesOfEncryptedData,
+ &decryptionKey, iv, 0 /* decrypt */);
+ offset += subSample.numBytesOfEncryptedData;
+ }
+}
- Pattern noPattern = {0, 0};
- vector<SubSample> subSamples = {{.numBytesOfClearData = kSegmentSize,
- .numBytesOfEncryptedData = 0}};
- uint64_t offset = 0;
+/**
+ * Test key status with empty session id, should return BAD_VALUE
+ */
+TEST_P(DrmHalVendorDecryptTest, QueryKeyStatusInvalidSession) {
+ SessionId sessionId;
+ auto res = drmPlugin->queryKeyStatus(sessionId,
+ [&](Status status, KeyedVector /* info */) {
+ EXPECT_EQ(Status::BAD_VALUE, status);
+ });
+ EXPECT_OK(res);
+}
+
+
+/**
+ * Test key status. There should be no key status prior to loading keys
+ */
+TEST_P(DrmHalVendorDecryptTest, QueryKeyStatusWithNoKeys) {
+ auto sessionId = openSession();
+ auto keyStatus = queryKeyStatus(sessionId);
+ EXPECT_EQ(0u, keyStatus.size());
+ closeSession(sessionId);
+}
+
+
+/**
+ * Test key status. There should be key status after loading keys.
+ */
+TEST_P(DrmHalVendorDecryptTest, QueryKeyStatus) {
+ for (auto config : contentConfigurations) {
auto sessionId = openSession();
loadKeys(sessionId, config);
-
- Status status = cryptoPlugin->setMediaDrmSession(sessionId);
- EXPECT_EQ(Status::OK, status);
-
- const bool kNotSecure = false;
- auto res = cryptoPlugin->decrypt(
- kNotSecure, toHidlArray(config.keys[0].keyId), iv,
- Mode::UNENCRYPTED, noPattern, subSamples, sourceBuffer, offset,
- destBuffer, [&](Status status, uint32_t bytesWritten,
- string detailedError) {
- EXPECT_EQ(Status::OK, status) << "Failure in decryption "
- "for configuration "
- << config.name << ": "
- << detailedError;
- EXPECT_EQ(bytesWritten, kSegmentSize);
- });
- EXPECT_OK(res);
- uint8_t* base = static_cast<uint8_t*>(
- static_cast<void*>(sharedMemory->getPointer()));
-
- EXPECT_EQ(0,
- memcmp(static_cast<void*>(base),
- static_cast<void*>(base + kSegmentSize), kSegmentSize))
- << "decrypt data mismatch";
+ auto keyStatus = queryKeyStatus(sessionId);
+ EXPECT_NE(0u, keyStatus.size());
closeSession(sessionId);
}
}
/**
+ * Positive decrypt test. "Decrypt" a single clear segment and verify.
+ */
+TEST_P(DrmHalVendorDecryptTest, ClearSegmentTest) {
+ for (auto config : contentConfigurations) {
+ for (auto key : config.keys) {
+ const size_t kSegmentSize = 1024;
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const vector<SubSample> subSamples = {{.numBytesOfClearData = kSegmentSize,
+ .numBytesOfEncryptedData = 0}};
+ auto sessionId = openSession();
+ loadKeys(sessionId, config);
+
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+
+ uint32_t byteCount = decrypt(Mode::UNENCRYPTED, key.isSecure, toHidlArray(key.keyId),
+ &iv[0], subSamples, noPattern, key.clearContentKey, Status::OK);
+ EXPECT_EQ(kSegmentSize, byteCount);
+
+ closeSession(sessionId);
+ }
+ }
+}
+
+/**
+ * Positive decrypt test. Decrypt a single segment using aes_ctr.
+ * Verify data matches.
+ */
+TEST_P(DrmHalVendorDecryptTest, EncryptedAesCtrSegmentTest) {
+ for (auto config : contentConfigurations) {
+ for (auto key : config.keys) {
+ const size_t kSegmentSize = 1024;
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const vector<SubSample> subSamples = {{.numBytesOfClearData = kSegmentSize,
+ .numBytesOfEncryptedData = 0}};
+ auto sessionId = openSession();
+ loadKeys(sessionId, config);
+
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+
+ uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure, toHidlArray(key.keyId),
+ &iv[0], subSamples, noPattern, key.clearContentKey, Status::OK);
+ EXPECT_EQ(kSegmentSize, byteCount);
+
+ closeSession(sessionId);
+ }
+ }
+}
+
+/**
+ * Negative decrypt test. Decrypt without loading keys.
+ */
+TEST_P(DrmHalVendorDecryptTest, EncryptedAesCtrSegmentTestNoKeys) {
+ for (auto config : contentConfigurations) {
+ for (auto key : config.keys) {
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const vector<SubSample> subSamples = {{.numBytesOfClearData = 256,
+ .numBytesOfEncryptedData = 256}};
+ auto sessionId = openSession();
+
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+
+ uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure,
+ toHidlArray(key.keyId), &iv[0], subSamples, noPattern,
+ key.clearContentKey, Status::ERROR_DRM_NO_LICENSE);
+ EXPECT_EQ(0u, byteCount);
+
+ closeSession(sessionId);
+ }
+ }
+}
+
+/**
+ * Test key removal. Load keys then remove them and verify that
+ * decryption can't be performed.
+ */
+TEST_P(DrmHalVendorDecryptTest, AttemptDecryptWithKeysRemoved) {
+ for (auto config : contentConfigurations) {
+ for (auto key : config.keys) {
+ vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
+ const Pattern noPattern = {0, 0};
+ const vector<SubSample> subSamples = {{.numBytesOfClearData = 256,
+ .numBytesOfEncryptedData = 256}};
+ auto sessionId = openSession();
+
+ Status status = cryptoPlugin->setMediaDrmSession(sessionId);
+ EXPECT_EQ(Status::OK, status);
+
+ loadKeys(sessionId, config);
+ removeKeys(sessionId);
+
+ uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure,
+ toHidlArray(key.keyId), &iv[0], subSamples, noPattern,
+ key.clearContentKey, Status::ERROR_DRM_DECRYPT);
+ EXPECT_EQ(0u, byteCount);
+
+ closeSession(sessionId);
+ }
+ }
+}
+
+
+/**
* Instantiate the set of test cases for each vendor module
*/
INSTANTIATE_TEST_CASE_P(
DrmHalVendorFactoryTestCases, DrmHalVendorFactoryTest,
- testing::ValuesIn(gVendorModules->getVendorModulePaths()));
+ testing::ValuesIn(gVendorModules->getPathList()));
INSTANTIATE_TEST_CASE_P(
DrmHalVendorPluginTestCases, DrmHalVendorPluginTest,
- testing::ValuesIn(gVendorModules->getVendorModulePaths()));
+ testing::ValuesIn(gVendorModules->getPathList()));
INSTANTIATE_TEST_CASE_P(
DrmHalVendorDecryptTestCases, DrmHalVendorDecryptTest,
- testing::ValuesIn(gVendorModules->getVendorModulePaths()));
+ testing::ValuesIn(gVendorModules->getPathList()));
int main(int argc, char** argv) {
- gVendorModules =
- new drm_vts::VendorModules("/data/nativetest/drm_hidl_test/vendor");
+#if defined(__LP64__)
+ const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+ const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+ gVendorModules = new drm_vts::VendorModules(kModulePath);
+ if (gVendorModules->getPathList().size() == 0) {
+ std::cerr << "No vendor modules found in " << kModulePath <<
+ ", exiting" << std::endl;
+ exit(-1);
+ }
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/drm/1.0/vts/functional/vendor/lib/libvtswidevine.so b/drm/1.0/vts/functional/vendor/lib/libvtswidevine.so
deleted file mode 100755
index d365b34..0000000
--- a/drm/1.0/vts/functional/vendor/lib/libvtswidevine.so
+++ /dev/null
Binary files differ
diff --git a/drm/1.0/vts/functional/vendor_modules.cpp b/drm/1.0/vts/functional/vendor_modules.cpp
index 34af6f8..bb232ae 100644
--- a/drm/1.0/vts/functional/vendor_modules.cpp
+++ b/drm/1.0/vts/functional/vendor_modules.cpp
@@ -29,44 +29,37 @@
using std::unique_ptr;
namespace drm_vts {
-vector<string> VendorModules::getVendorModulePaths() {
- if (mModuleList.size() > 0) {
- return mModuleList;
- }
-
- DIR* dir = opendir(mModulesPath.c_str());
+void VendorModules::scanModules(const std::string &directory) {
+ DIR* dir = opendir(directory.c_str());
if (dir == NULL) {
- ALOGE("Unable to open drm VTS vendor directory %s",
- mModulesPath.c_str());
- return mModuleList;
- }
-
- struct dirent* entry;
- while ((entry = readdir(dir))) {
- string fullpath = mModulesPath + "/" + entry->d_name;
- if (endsWith(fullpath, ".so")) {
- mModuleList.push_back(fullpath);
+ ALOGE("Unable to open drm VTS vendor directory %s", directory.c_str());
+ } else {
+ struct dirent* entry;
+ while ((entry = readdir(dir))) {
+ ALOGD("checking file %s", entry->d_name);
+ string fullpath = directory + "/" + entry->d_name;
+ if (endsWith(fullpath, ".so")) {
+ mPathList.push_back(fullpath);
+ }
}
+ closedir(dir);
}
-
- closedir(dir);
- return mModuleList;
}
-DrmHalVTSVendorModule* VendorModules::getVendorModule(const string& path) {
- unique_ptr<SharedLibrary>& library = mOpenLibraries[path];
- if (!library) {
- library = unique_ptr<SharedLibrary>(new SharedLibrary(path));
+DrmHalVTSVendorModule* VendorModules::getModule(const string& path) {
+ if (mOpenLibraries.find(path) == mOpenLibraries.end()) {
+ auto library = std::make_unique<SharedLibrary>(path);
if (!library) {
ALOGE("failed to map shared library %s", path.c_str());
return NULL;
}
+ mOpenLibraries[path] = std::move(library);
}
+ const unique_ptr<SharedLibrary>& library = mOpenLibraries[path];
void* symbol = library->lookup("vendorModuleFactory");
if (symbol == NULL) {
ALOGE("getVendorModule failed to lookup 'vendorModuleFactory' in %s: "
- "%s",
- path.c_str(), library->lastError());
+ "%s", path.c_str(), library->lastError());
return NULL;
}
typedef DrmHalVTSVendorModule* (*ModuleFactory)();
diff --git a/drm/1.0/vts/functional/vendor_modules.h b/drm/1.0/vts/functional/vendor_modules.h
index 5371a0d..ca538f6 100644
--- a/drm/1.0/vts/functional/vendor_modules.h
+++ b/drm/1.0/vts/functional/vendor_modules.h
@@ -30,27 +30,33 @@
* Initialize with a file system path where the shared libraries
* are to be found.
*/
- explicit VendorModules(const std::string& path) : mModulesPath(path) {}
+ explicit VendorModules(const std::string& dir) {
+ scanModules(dir);
+ }
~VendorModules() {}
/**
- * Return a list of paths to available vendor modules.
- */
- std::vector<std::string> getVendorModulePaths();
-
- /**
* Retrieve a DrmHalVTSVendorModule given its full path. The
* getAPIVersion method can be used to determine the versioned
* subclass type.
*/
- DrmHalVTSVendorModule* getVendorModule(const std::string& path);
+ DrmHalVTSVendorModule* getModule(const std::string& path);
+
+ /**
+ * Return the list of paths to available vendor modules.
+ */
+ std::vector<std::string> getPathList() const {return mPathList;}
private:
- std::string mModulesPath;
- std::vector<std::string> mModuleList;
+ std::vector<std::string> mPathList;
std::map<std::string, std::unique_ptr<SharedLibrary>> mOpenLibraries;
- inline bool endsWith(const std::string& str, const std::string& suffix) {
+ /**
+ * Scan the list of paths to available vendor modules.
+ */
+ void scanModules(const std::string& dir);
+
+ inline bool endsWith(const std::string& str, const std::string& suffix) const {
if (suffix.size() > str.size()) return false;
return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
}
diff --git a/keymaster/3.0/vts/functional/Android.mk b/keymaster/3.0/vts/functional/Android.mk
index 4265b9f..4098664 100644
--- a/keymaster/3.0/vts/functional/Android.mk
+++ b/keymaster/3.0/vts/functional/Android.mk
@@ -15,7 +15,7 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := keymaster_hidl_hal_test
+LOCAL_MODULE := VtsHalKeymasterV3_0TargetTest
LOCAL_SRC_FILES := \
authorization_set.cpp \
attestation_record.cpp \
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index 2382f0b..edb1cd1 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -46,6 +46,8 @@
// non-gtest argument will be used as the service name.
string service_name = "default";
+static bool arm_deleteAllKeys = false;
+
namespace android {
namespace hardware {
@@ -488,13 +490,20 @@
return ExportKey(format, key_blob_, client_id, app_data, key_material);
}
- ErrorCode DeleteKey(HidlBuf* key_blob) {
+ ErrorCode DeleteKey(HidlBuf* key_blob, bool keep_key_blob = false) {
ErrorCode error = keymaster_->deleteKey(*key_blob);
- *key_blob = HidlBuf();
+ if (!keep_key_blob) *key_blob = HidlBuf();
return error;
}
- ErrorCode DeleteKey() { return DeleteKey(&key_blob_); }
+ ErrorCode DeleteKey(bool keep_key_blob = false) {
+ return DeleteKey(&key_blob_, keep_key_blob);
+ }
+
+ ErrorCode DeleteAllKeys() {
+ ErrorCode error = keymaster_->deleteAllKeys();
+ return error;
+ }
ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
const HidlBuf& app_data, KeyCharacteristics* key_characteristics) {
@@ -3893,6 +3902,124 @@
&cert_chain));
}
+typedef KeymasterHidlTest KeyDeletionTest;
+
+/**
+ * KeyDeletionTest.DeleteKey
+ *
+ * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
+ * valid key blob.
+ */
+TEST_F(KeyDeletionTest, DeleteKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ // Delete must work if rollback protection is implemented
+ AuthorizationSet teeEnforced(key_characteristics_.teeEnforced);
+ bool rollback_protected = teeEnforced.Contains(TAG_ROLLBACK_RESISTANT);
+
+ if (rollback_protected) {
+ ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
+ } else {
+ auto delete_result = DeleteKey(true /* keep key blob */);
+ ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
+ }
+
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
+
+ if (rollback_protected) {
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ }
+ AbortIfNeeded();
+ key_blob_ = HidlBuf();
+}
+
+/**
+ * KeyDeletionTest.DeleteInvalidKey
+ *
+ * This test checks that the HAL excepts invalid key blobs.
+ */
+TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+ // Generate key just to check if rollback protection is implemented
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ // Delete must work if rollback protection is implemented
+ AuthorizationSet teeEnforced(key_characteristics_.teeEnforced);
+ bool rollback_protected = teeEnforced.Contains(TAG_ROLLBACK_RESISTANT);
+
+ // Delete the key we don't care about the result at this point.
+ DeleteKey();
+
+ // Now create an invalid key blob and delete it.
+ key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
+
+ if (rollback_protected) {
+ ASSERT_EQ(ErrorCode::OK, DeleteKey());
+ } else {
+ auto delete_result = DeleteKey();
+ ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
+ }
+}
+
+/**
+ * KeyDeletionTest.DeleteAllKeys
+ *
+ * This test is disarmed by default. To arm it use --arm_deleteAllKeys.
+ *
+ * BEWARE: This test has serious side effects. All user keys will be lost! This includes
+ * FBE/FDE encryption keys, which means that the device will not even boot until after the
+ * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
+ * been provisioned. Use this test only on dedicated testing devices that have no valuable
+ * credentials stored in Keystore/Keymaster.
+ */
+TEST_F(KeyDeletionTest, DeleteAllKeys) {
+ if (!arm_deleteAllKeys) return;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ // Delete must work if rollback protection is implemented
+ AuthorizationSet teeEnforced(key_characteristics_.teeEnforced);
+ bool rollback_protected = teeEnforced.Contains(TAG_ROLLBACK_RESISTANT);
+
+ ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
+
+ if (rollback_protected) {
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ }
+ AbortIfNeeded();
+ key_blob_ = HidlBuf();
+}
+
} // namespace test
} // namespace V3_0
} // namespace keymaster
@@ -3901,9 +4028,19 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- if (argc == 2) {
- ALOGI("Running keymaster VTS against service \"%s\"", argv[1]);
- service_name = argv[1];
+ std::vector<std::string> positional_args;
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ if (std::string(argv[i]) == "--arm_deleteAllKeys") {
+ arm_deleteAllKeys = true;
+ }
+ } else {
+ positional_args.push_back(argv[i]);
+ }
+ }
+ if (positional_args.size()) {
+ ALOGI("Running keymaster VTS against service \"%s\"", positional_args[0].c_str());
+ service_name = positional_args[0];
}
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index a65c7b8..14c4a2a 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -616,7 +616,7 @@
switch (type) {
#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
- case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType); break;
+ case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType.c_str()); break;
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
diff --git a/usb/1.0/default/service.cpp b/usb/1.0/default/service.cpp
index 4605a4c..43ab6f0 100644
--- a/usb/1.0/default/service.cpp
+++ b/usb/1.0/default/service.cpp
@@ -27,13 +27,21 @@
using android::hardware::usb::V1_0::IUsb;
using android::hardware::usb::V1_0::implementation::Usb;
+using android::status_t;
+using android::OK;
+
int main() {
android::sp<IUsb> service = new Usb();
configureRpcThreadpool(1, true /*callerWillJoin*/);
- service->registerAsService();
+ status_t status = service->registerAsService();
- ALOGI("USB HAL Ready.");
- joinRpcThreadpool();
+ if (status == OK) {
+ ALOGI("USB HAL Ready.");
+ joinRpcThreadpool();
+ }
+
+ ALOGE("Cannot register USB HAL service");
+ return 1;
}
diff --git a/wifi/1.0/default/hidl_callback_util.h b/wifi/1.0/default/hidl_callback_util.h
index 7136279..b7100c8 100644
--- a/wifi/1.0/default/hidl_callback_util.h
+++ b/wifi/1.0/default/hidl_callback_util.h
@@ -82,7 +82,7 @@
return true;
}
- const std::set<android::sp<CallbackType>> getCallbacks() { return cb_set_; }
+ const std::set<android::sp<CallbackType>>& getCallbacks() { return cb_set_; }
// Death notification for callbacks.
void onObjectDeath(uint64_t cookie) {
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index df9c9df..83b2e53 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -417,17 +417,25 @@
const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
if (next_ie + curr_ie_len > ies_end) {
- return false;
+ LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void *)next_ie
+ << ", Curr IE len: " << curr_ie_len << ", IEs End: " << (void *)ies_end;
+ break;
}
WifiInformationElement hidl_ie;
if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
- return false;
+ LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
+ << ", len: " << legacy_ie.len;
+ break;
}
hidl_ies->push_back(std::move(hidl_ie));
next_ie += curr_ie_len;
}
- // Ensure that the blob has been fully consumed.
- return (next_ie == ies_end);
+ // Check if the blob has been fully consumed.
+ if (next_ie != ies_end) {
+ LOG(ERROR) << "Failed to fully parse IE blob. Next IE: " << (void *)next_ie
+ << ", IEs End: " << (void *)ies_end;
+ }
+ return true;
}
bool convertLegacyGscanResultToHidl(
diff --git a/wifi/1.0/default/wifi_chip.cpp b/wifi/1.0/default/wifi_chip.cpp
index 9c41a40..319e126 100644
--- a/wifi/1.0/default/wifi_chip.cpp
+++ b/wifi/1.0/default/wifi_chip.cpp
@@ -855,7 +855,8 @@
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->onDebugRingBufferDataAvailable(hidl_status, data).isOk()) {
LOG(ERROR) << "Failed to invoke onDebugRingBufferDataAvailable"
- << " callback";
+ << " callback on: " << toString(callback);
+
}
}
};