Add remote access HAL interface and ref impl. am: 7a5283fda1
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2269305
Change-Id: I3c61306d7ceccc1fdcb3a20d88236011e9f82585
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/README.md b/audio/README.md
index 3f40d72..1938ad4 100644
--- a/audio/README.md
+++ b/audio/README.md
@@ -2,29 +2,10 @@
Directory structure of the audio HAL related code.
-## Directory Structure for AIDL audio HAL
+Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
+based on an existing one.
-The AIDL version is located inside `aidl` directory. The tree below explains
-the role of each subdirectory:
-
-* `aidl_api` — snapshots of the API created each Android release. Every
- release, the current version of the API becomes "frozen" and gets assigned
- the next version number. If the API needs further modifications, they are
- made on the "current" version. After making modifications, run
- `m <package name>-update-api` to update the snapshot of the "current"
- version.
-* `android/hardware/audio/common` — data structures and interfaces shared
- between various HALs: BT HAL, core and effects audio HALs.
-* `android/hardware/audio/core` — data structures and interfaces of the
- core audio HAL.
-* `default` — the default, reference implementation of the audio HAL service.
-* `vts` — VTS tests for the AIDL HAL.
-
-## Directory Structure for HIDL audio HAL
-
-Run `common/all-versions/copyHAL.sh` to create a new version of the HIDL audio
-HAL based on an existing one. Note that this isn't possible since Android T
-release. Android U and above uses AIDL audio HAL.
+## Directory Structure
* `2.0` — version 2.0 of the core HIDL API. Note that `.hal` files
can not be moved into the `core` directory because that would change
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 3baafc9..b57dc63 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -238,12 +238,27 @@
}
// static
-std::vector<uint8_t> Effect::parameterToHal(uint32_t paramSize, const void* paramData,
- uint32_t valueSize, const void** valueData) {
+bool Effect::parameterToHal(uint32_t paramSize, const void* paramData, uint32_t valueSize,
+ const void** valueData, std::vector<uint8_t>* halParamBuffer) {
+ constexpr size_t kMaxSize = EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t);
+ if (paramSize > kMaxSize) {
+ ALOGE("%s: Parameter size is too big: %" PRIu32, __func__, paramSize);
+ return false;
+ }
size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
+ if (valueOffsetFromData > kMaxSize) {
+ ALOGE("%s: Aligned parameter size is too big: %zu", __func__, valueOffsetFromData);
+ return false;
+ }
+ if (valueSize > kMaxSize - valueOffsetFromData) {
+ ALOGE("%s: Value size is too big: %" PRIu32 ", max size is %zu", __func__, valueSize,
+ kMaxSize - valueOffsetFromData);
+ android_errorWriteLog(0x534e4554, "237291425");
+ return false;
+ }
size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
- std::vector<uint8_t> halParamBuffer(halParamBufferSize, 0);
- effect_param_t* halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
+ halParamBuffer->resize(halParamBufferSize, 0);
+ effect_param_t* halParam = reinterpret_cast<effect_param_t*>(halParamBuffer->data());
halParam->psize = paramSize;
halParam->vsize = valueSize;
memcpy(halParam->data, paramData, paramSize);
@@ -256,7 +271,7 @@
*valueData = halParam->data + valueOffsetFromData;
}
}
- return halParamBuffer;
+ return true;
}
Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
@@ -301,6 +316,11 @@
Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
GetCurrentConfigSuccessCallback onSuccess) {
+ if (configSize > kMaxDataSize - sizeof(uint32_t)) {
+ ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
+ android_errorWriteLog(0x534e4554, "240266798");
+ return Result::INVALID_ARGUMENTS;
+ }
uint32_t halCmd = featureId;
std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
uint32_t halResultSize = 0;
@@ -314,11 +334,15 @@
GetParameterSuccessCallback onSuccess) {
// As it is unknown what method HAL uses for copying the provided parameter data,
// it is safer to make sure that input and output buffers do not overlap.
- std::vector<uint8_t> halCmdBuffer =
- parameterToHal(paramSize, paramData, requestValueSize, nullptr);
+ std::vector<uint8_t> halCmdBuffer;
+ if (!parameterToHal(paramSize, paramData, requestValueSize, nullptr, &halCmdBuffer)) {
+ return Result::INVALID_ARGUMENTS;
+ }
const void* valueData = nullptr;
- std::vector<uint8_t> halParamBuffer =
- parameterToHal(paramSize, paramData, replyValueSize, &valueData);
+ std::vector<uint8_t> halParamBuffer;
+ if (!parameterToHal(paramSize, paramData, replyValueSize, &valueData, &halParamBuffer)) {
+ return Result::INVALID_ARGUMENTS;
+ }
uint32_t halParamBufferSize = halParamBuffer.size();
return sendCommandReturningStatusAndData(
@@ -331,8 +355,12 @@
Result Effect::getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
GetSupportedConfigsSuccessCallback onSuccess) {
+ if (maxConfigs != 0 && configSize > (kMaxDataSize - 2 * sizeof(uint32_t)) / maxConfigs) {
+ ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
+ return Result::INVALID_ARGUMENTS;
+ }
uint32_t halCmd[2] = {featureId, maxConfigs};
- uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
+ uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * configSize;
std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
return sendCommandReturningStatusAndData(
EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
@@ -472,8 +500,10 @@
Result Effect::setParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
const void* valueData) {
- std::vector<uint8_t> halParamBuffer =
- parameterToHal(paramSize, paramData, valueSize, &valueData);
+ std::vector<uint8_t> halParamBuffer;
+ if (!parameterToHal(paramSize, paramData, valueSize, &valueData, &halParamBuffer)) {
+ return Result::INVALID_ARGUMENTS;
+ }
return sendCommandReturningStatus(EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(),
&halParamBuffer[0]);
}
diff --git a/audio/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h
index 011544d..5d8dccc 100644
--- a/audio/effect/all-versions/default/Effect.h
+++ b/audio/effect/all-versions/default/Effect.h
@@ -184,6 +184,9 @@
using GetSupportedConfigsSuccessCallback =
std::function<void(uint32_t supportedConfigs, void* configsData)>;
+ // Sets the limit on the maximum size of vendor-provided data structures.
+ static constexpr size_t kMaxDataSize = 1 << 20;
+
static const char* sContextResultOfCommand;
static const char* sContextCallToCommand;
static const char* sContextCallFunction;
@@ -211,8 +214,8 @@
channel_config_t* halConfig);
static void effectOffloadParamToHal(const EffectOffloadParameter& offload,
effect_offload_param_t* halOffload);
- static std::vector<uint8_t> parameterToHal(uint32_t paramSize, const void* paramData,
- uint32_t valueSize, const void** valueData);
+ static bool parameterToHal(uint32_t paramSize, const void* paramData, uint32_t valueSize,
+ const void** valueData, std::vector<uint8_t>* halParamBuffer);
Result analyzeCommandStatus(const char* commandName, const char* context, status_t status);
void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb);
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index e59423f..d95bb06 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -35,6 +35,7 @@
#include <common/all-versions/VersionUtils.h>
+#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -623,6 +624,27 @@
EXPECT_TRUE(ret.isOk());
}
+TEST_P(AudioEffectHidlTest, GetParameterInvalidMaxReplySize) {
+ description("Verify that GetParameter caps the maximum reply size");
+ const bool isNewDeviceLaunchingOnTPlus = property_get_int32("ro.vendor.api_level", 0) >= 33;
+ if (!isNewDeviceLaunchingOnTPlus) {
+ GTEST_SKIP() << "The test only applies to devices launching on T or later";
+ }
+ // Use a non-empty parameter to avoid being rejected by any earlier checks.
+ hidl_vec<uint8_t> parameter;
+ parameter.resize(16);
+ // Use very large size to ensure that the service does not crash. Since parameters
+ // are specific to each effect, and some effects may not have parameters at all,
+ // simply checking the return value would not reveal an issue of using an uncapped value.
+ const uint32_t veryLargeReplySize = std::numeric_limits<uint32_t>::max() - 100;
+ Result retval = Result::OK;
+ Return<void> ret =
+ effect->getParameter(parameter, veryLargeReplySize,
+ [&](Result r, const hidl_vec<uint8_t>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, retval);
+}
+
TEST_P(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
description("Verify that GetSupportedConfigsForFeature does not crash");
Return<void> ret = effect->getSupportedConfigsForFeature(
@@ -643,6 +665,37 @@
EXPECT_TRUE(ret.isOk());
}
+TEST_P(AudioEffectHidlTest, GetSupportedConfigsForFeatureInvalidConfigSize) {
+ description("Verify that GetSupportedConfigsForFeature caps the maximum config size");
+ const bool isNewDeviceLaunchingOnTPlus = property_get_int32("ro.vendor.api_level", 0) >= 33;
+ if (!isNewDeviceLaunchingOnTPlus) {
+ GTEST_SKIP() << "The test only applies to devices launching on T or later";
+ }
+ // Use very large size to ensure that the service does not crash.
+ const uint32_t veryLargeConfigSize = std::numeric_limits<uint32_t>::max() - 100;
+ Result retval = Result::OK;
+ Return<void> ret = effect->getSupportedConfigsForFeature(
+ 0, 1, veryLargeConfigSize,
+ [&](Result r, uint32_t, const hidl_vec<uint8_t>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, retval);
+}
+
+TEST_P(AudioEffectHidlTest, GetCurrentConfigForFeatureInvalidConfigSize) {
+ description("Verify that GetCurrentConfigForFeature caps the maximum config size");
+ const bool isNewDeviceLaunchingOnTPlus = property_get_int32("ro.vendor.api_level", 0) >= 33;
+ if (!isNewDeviceLaunchingOnTPlus) {
+ GTEST_SKIP() << "The test only applies to devices launching on T or later";
+ }
+ // Use very large size to ensure that the service does not crash.
+ const uint32_t veryLargeConfigSize = std::numeric_limits<uint32_t>::max() - 100;
+ Result retval = Result::OK;
+ Return<void> ret = effect->getCurrentConfigForFeature(
+ 0, veryLargeConfigSize, [&](Result r, const hidl_vec<uint8_t>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, retval);
+}
+
// The main test class for Equalizer Audio Effect HIDL HAL.
class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest {
public:
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
index ebff98f..3abdb54 100644
--- a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
@@ -33,7 +33,9 @@
@utf8InCpp
String deviceId;
/**
- * Possible additional vendor information that is opaque to the EvsManager
+ * Possible additional vendor information that is opaque to the EvsManager.
+ * The size of the payload must not exceed 16-byte if the HIDL recipients are
+ * expected to exist.
*/
int[] payload;
}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
index 2c2b44c..c599d58 100644
--- a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
@@ -47,7 +47,10 @@
/**
* Receives calls from the HAL each time an event happens.
*
- * @param in event EVS event with possible event information.
+ * @param in event EVS event with possible event information. If ths HIDL
+ * recipients are expected to exist, the size of the event
+ * payload must not exceed 16 bytes; otherwise, a notification
+ * will not reach them.
*/
void notify(in EvsEventDesc event);
}
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 0d3253b..33e211c 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -84,7 +84,10 @@
name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
vendor: true,
defaults: ["vhal_v2_0_target_defaults"],
- cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
+ cflags: [
+ "-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING",
+ "-DENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS",
+ ],
srcs: [
"impl/vhal_v2_0/DefaultVehicleHal.cpp",
"impl/vhal_v2_0/VehicleHalClient.cpp",
@@ -225,6 +228,25 @@
test_suites: ["general-tests"],
}
+cc_test {
+ name: "android.hardware.automotive.vehicle@2.0-default-config-test",
+ vendor: true,
+ defaults: ["vhal_v2_0_target_defaults"],
+ srcs: [
+ "impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp",
+ ],
+ cflags: [
+ "-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING",
+ "-DENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "libgtest",
+ "libgmock",
+ ],
+ test_suites: ["general-tests"],
+}
+
cc_binary {
name: "android.hardware.automotive.vehicle@2.0-default-service",
defaults: ["vhal_v2_0_target_defaults"],
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 cfbbbd3..55a7720 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
@@ -1109,6 +1109,19 @@
},
.initialValue = {.stringValue = {"Test"}},
},
+ // This property is later defined in the AIDL VHAL interface. However, HIDL VHAL might
+ // require support for this property to meet EU regulation.
+ {
+ .config =
+ {
+ // GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT
+ .prop = 0x11400F47,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ // GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1
+ .initialValue = {.int32Values = {1}},
+ },
#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
// Vendor propetry for E2E ClusterHomeService testing.
{
@@ -1157,6 +1170,46 @@
},
},
#endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+#ifdef ENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS
+ {
+ .config =
+ {
+ // VHAL_SUPPORTED_PROPERTY_IDS
+ .prop = 289476424,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ // Fetch 100 configs in one request. This number is just arbitrarily
+ // chosen here. But some HAL impl with bigger config data may need a
+ // smaller number.
+ .configArray = {100},
+ },
+ // All supported property IDs. This list is checked by
+ // DefaultConfigSupportedPropertyIds_test.
+ .initialValue =
+ {.int32Values =
+ {291504388, 289472773, 291504390, 289472775, 289407240, 289407241,
+ 289472780, 286261505, 286261506, 289407235, 289472779, 291504647,
+ 289408517, 356518832, 356516106, 291504644, 291504649, 291504656,
+ 291504901, 291504903, 287310600, 291504905, 287310602, 287310603,
+ 291504908, 291504904, 392168201, 392168202, 289408514, 289408001,
+ 287310850, 287310851, 287310853, 289475088, 289475104, 289475120,
+ 354419984, 320865540, 320865556, 354419975, 354419976, 354419986,
+ 354419973, 354419974, 354419978, 354419977, 356517120, 356517121,
+ 356582673, 356517139, 289408269, 356517131, 358614275, 291570965,
+ 291505923, 289408270, 289408512, 287310855, 289408000, 289408008,
+ 289408009, 289407747, 291504900, 568332561, 371198722, 373295872,
+ 320867268, 322964416, 290521862, 287310858, 287310859, 289475072,
+ 289475073, 289409539, 299896064, 299896065, 299896066, 299896067,
+ 289410560, 289410561, 289410562, 289410563, 289410576, 289410577,
+ 289410578, 289410579, 289476368, 299895808, 639631617, 627048706,
+ 591397123, 554696964, 289410873, 289410874, 287313669, 299896583,
+ 299896584, 299896585, 299896586, 299896587, 286265121, 286265122,
+ 286265123, 290457094, 290459441, 299896626, 290459443, 289410868,
+ 289476405, 299896630, 289410871, 292556600, 557853201, 559950353,
+ 555756049, 554707473, 289410887, 557846324, 557911861, 568332086,
+ 557846327, 560992056, 289476424}},
+ },
+#endif // ENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp
new file mode 100644
index 0000000..aa05daa
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <vector>
+
+#include "vhal_v2_0/DefaultConfig.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+
+using ::testing::ElementsAreArray;
+
+// Test that VHAL_SUPPORTED_PROPERTY_IDS contains all supported property IDs.
+TEST(DefaultConfigSupportedPropertyIdsTest, testIncludeAllSupportedIds) {
+ const int32_t vhalSupportedPropertyIdsPropId = 289476424;
+
+ std::vector<int32_t> allSupportedIds;
+ std::vector<int32_t> configuredSupportedIds;
+
+ for (const auto& property : impl::kVehicleProperties) {
+ int propId = property.config.prop;
+ allSupportedIds.push_back(propId);
+
+ if (propId == vhalSupportedPropertyIdsPropId) {
+ configuredSupportedIds = property.initialValue.int32Values;
+ }
+ }
+
+ ASSERT_THAT(allSupportedIds, ElementsAreArray(configuredSupportedIds));
+}
+
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index e3c8dd6..25a1940 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -141,7 +141,7 @@
TEST_F(DefaultVhalImplTest, testListProperties) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
- EXPECT_EQ((size_t)121, configs.size());
+ EXPECT_EQ((size_t)123, configs.size());
}
TEST_F(DefaultVhalImplTest, testGetDefaultPropertyFloat) {
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index e00f775..9a93e1a 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -40,6 +40,7 @@
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
using ::aidl::android::hardware::automotive::vehicle::VehicleGear;
using ::aidl::android::hardware::automotive::vehicle::VehicleHvacFanDirection;
@@ -124,6 +125,13 @@
{.config =
{
+ .prop = toInt(VehicleProperty::INFO_VIN),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+ .initialValue = {.stringValue = "1GCARVIN123456789"}},
+ {.config =
+ {
.prop = toInt(VehicleProperty::INFO_MAKE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
@@ -173,6 +181,523 @@
{.config =
{
+ .prop = toInt(VehicleProperty::EV_BATTERY_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {toInt(VehicleUnit::WATT_HOUR),
+ toInt(VehicleUnit::AMPERE_HOURS),
+ toInt(VehicleUnit::KILOWATT_HOUR)},
+ },
+ .initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_BUCKLED),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_HEIGHT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = 0,
+ .maxInt32Value = 10}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {10}}},
+ {SEAT_1_RIGHT, {.int32Values = {10}}},
+ {SEAT_2_LEFT, {.int32Values = {10}}},
+ {SEAT_2_RIGHT, {.int32Values = {10}}},
+ {SEAT_2_CENTER, {.int32Values = {10}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_HEIGHT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_FORE_AFT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_FORE_AFT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BACKREST_ANGLE_1_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BACKREST_ANGLE_1_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BACKREST_ANGLE_2_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_BACKREST_ANGLE_2_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
+ {SEAT_1_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_LEFT, {.int32Values = {0}}},
+ {SEAT_2_RIGHT, {.int32Values = {0}}},
+ {SEAT_2_CENTER, {.int32Values = {0}}}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEIGHT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEIGHT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_DEPTH_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_DEPTH_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_TILT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_TILT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_LUMBAR_FORE_AFT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -10,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -10,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_LUMBAR_FORE_AFT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = 0,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEADREST_ANGLE_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = 0,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEADREST_ANGLE_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEADREST_FORE_AFT_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 10},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = 0,
+ .maxInt32Value = 10}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::SEAT_OCCUPANCY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -352,8 +877,9 @@
.prop = toInt(VehicleProperty::VEHICLE_CURB_WEIGHT),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
+ .configArray = {/*gross weight kg=*/2948},
},
- .initialValue = {.int32Values = {30}}},
+ .initialValue = {.int32Values = {2211 /*kg*/}}},
{.config =
{
@@ -460,6 +986,24 @@
{.config =
{
+ .prop = toInt(VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {(int)VehicleUnit::LITER, (int)VehicleUnit::US_GALLON},
+ },
+ .initialValue = {.int32Values = {(int)VehicleUnit::LITER}}},
+
+ {.config =
+ {
+ .prop = toInt(
+ VehicleProperty::FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {1}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::HW_KEY_INPUT),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -486,6 +1030,12 @@
.int32Values = {0, 0, 0},
}},
+ {.config = {.prop = toInt(VehicleProperty::HVAC_ACTUAL_FAN_SPEED_RPM),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+ .initialValue = {.int32Values = {50}}},
+
{.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -623,6 +1173,25 @@
}}},
.initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
+ {.config = {.prop = toInt(VehicleProperty::HVAC_SIDE_MIRROR_HEAT),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaMirror::DRIVER_LEFT) |
+ toInt(VehicleAreaMirror::DRIVER_RIGHT),
+ .minInt32Value = 0,
+ .maxInt32Value = 2,
+ }}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_CURRENT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_LEFT},
+ VehicleAreaConfig{.areaId = HVAC_RIGHT}}},
+ .initialAreaValues = {{HVAC_LEFT, {.floatValues = {17.3f}}},
+ {HVAC_RIGHT, {.floatValues = {19.1f}}}}},
+
{.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -715,6 +1284,16 @@
{.config =
{
+ .prop = toInt(VehicleProperty::ENGINE_COOLANT_TEMP),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 10.0f,
+ },
+ .initialValue = {.floatValues = {75.0f}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -774,6 +1353,76 @@
.areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}},
.initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::MIRROR_Z_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_LEFT),
+ .minInt32Value = -3,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_RIGHT),
+ .minInt32Value = -3,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_CENTER),
+ .minInt32Value = -3,
+ .maxInt32Value = 3}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::MIRROR_Z_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_LEFT),
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_RIGHT),
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_CENTER),
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::MIRROR_Y_POS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_LEFT),
+ .minInt32Value = -3,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_RIGHT),
+ .minInt32Value = -3,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_CENTER),
+ .minInt32Value = -3,
+ .maxInt32Value = 3}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::MIRROR_Y_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_LEFT),
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_RIGHT),
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = toInt(VehicleAreaMirror::DRIVER_CENTER),
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
+ {.config = {.prop = toInt(VehicleProperty::MIRROR_LOCK),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .initialValue = {.int32Values = {1}}},
+
+ {.config = {.prop = toInt(VehicleProperty::MIRROR_FOLD),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .initialValue = {.int32Values = {1}}},
+
{.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -802,6 +1451,26 @@
.maxInt32Value = 10}}},
.initialValue = {.int32Values = {0}}},
+ {.config = {.prop = toInt(VehicleProperty::WINDOW_MOVE),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = WINDOW_1_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = WINDOW_2_LEFT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = WINDOW_2_RIGHT,
+ .minInt32Value = -1,
+ .maxInt32Value = 1},
+ VehicleAreaConfig{.areaId = WINDOW_ROOF_TOP_1,
+ .minInt32Value = -1,
+ .maxInt32Value = 1}}},
+ .initialValue = {.int32Values = {0}}},
+
{.config =
{
.prop = WHEEL_TICK,
@@ -884,14 +1553,6 @@
{.config =
{
- .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
- {.config =
- {
.prop = toInt(VehicleProperty::FRONT_FOG_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -916,6 +1577,24 @@
{.config =
{
+ .prop = toInt(VehicleProperty::CABIN_LIGHTS_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+ {.config = {.prop = toInt(VehicleProperty::READING_LIGHTS_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER}}},
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -930,14 +1609,7 @@
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
-
+ // FOG_LIGHTS_SWITCH must not be implemented when FRONT_FOG_LIGHTS_SWITCH is implemented
{.config =
{
.prop = toInt(VehicleProperty::FRONT_FOG_LIGHTS_SWITCH),
@@ -946,6 +1618,7 @@
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+ // FOG_LIGHTS_SWITCH must not be implemented when REAR_FOG_LIGHTS_SWITCH is implemented
{.config =
{
.prop = toInt(VehicleProperty::REAR_FOG_LIGHTS_SWITCH),
@@ -964,6 +1637,24 @@
{.config =
{
+ .prop = toInt(VehicleProperty::CABIN_LIGHTS_SWITCH),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+ {.config = {.prop = toInt(VehicleProperty::READING_LIGHTS_SWITCH),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT},
+ VehicleAreaConfig{.areaId = SEAT_2_CENTER}}},
+ .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+ {.config =
+ {
.prop = toInt(VehicleProperty::EVS_SERVICE_REQUEST),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index b64c1a6..20c34aa 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -217,17 +217,16 @@
[[fallthrough]];
case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
// CPMS is in WAIT_FOR_VHAL state, simply move to ON and send back to HAL.
- // Must erase existing state because in the case when Car Service crashes, the power
- // state would already be ON when we receive WAIT_FOR_VHAL and thus new property change
- // event would be generated. However, Car Service always expect a property change event
- // even though there is not actual state change.
- mServerSidePropStore->removeValuesForProperty(
- toInt(VehicleProperty::AP_POWER_STATE_REQ));
prop = createApPowerStateReq(VehicleApPowerStateReq::ON);
- // ALWAYS update status for generated property value
+ // ALWAYS update status for generated property value, and force a property update event
+ // because in the case when Car Service crashes, the power state would already be ON
+ // when we receive WAIT_FOR_VHAL and thus new property change event would be generated.
+ // However, Car Service always expect a property change event even though there is no
+ // actual state change.
if (auto writeResult =
- mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
+ mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true,
+ VehiclePropertyStore::EventMode::ALWAYS);
!writeResult.ok()) {
return StatusError(getErrorCode(writeResult))
<< "failed to write AP_POWER_STATE_REQ into property store, error: "
@@ -894,10 +893,10 @@
return;
}
result.value()->timestamp = elapsedRealtimeNano();
- // Must remove the value before writing, otherwise, we would generate no update event since
- // the value is the same.
- mServerSidePropStore->removeValue(*result.value());
- mServerSidePropStore->writeValue(std::move(result.value()));
+ // For continuous properties, we must generate a new onPropertyChange event periodically
+ // according to the sample rate.
+ mServerSidePropStore->writeValue(std::move(result.value()), /*updateStatus=*/true,
+ VehiclePropertyStore::EventMode::ALWAYS);
});
mRecurrentTimer->registerTimerCallback(interval, action);
mRecurrentActions[propIdAreaId] = action;
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index a7fcdcf..8bc3c20 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -42,6 +42,7 @@
#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleArea.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleAreaDoor.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleAreaMirror.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleAreaSeat.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleAreaWheel.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleAreaWindow.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index ddc4f68..3d25cd3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -46,6 +46,33 @@
using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
using ValuesResultType = VhalResult<std::vector<VehiclePropValuePool::RecyclableType>>;
+ enum class EventMode : uint8_t {
+ /**
+ * Only invoke OnValueChangeCallback if the new property value (ignoring timestamp) is
+ * different than the existing value.
+ *
+ * This should be used for regular cases.
+ */
+ ON_VALUE_CHANGE,
+ /**
+ * Always invoke OnValueChangeCallback.
+ *
+ * This should be used for the special properties that are used for delivering event, e.g.
+ * HW_KEY_INPUT.
+ */
+ ALWAYS,
+ /**
+ * Never invoke OnValueChangeCallback.
+ *
+ * This should be used for continuous property subscription when the sample rate for the
+ * subscription is smaller than the refresh rate for the property. E.g., the vehicle speed
+ * is refreshed at 20hz, but we are only subscribing at 10hz. In this case, we want to
+ * generate the property change event at 10hz, not 20hz, but we still want to refresh the
+ * timestamp (via writeValue) at 20hz.
+ */
+ NEVER,
+ };
+
explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
: mValuePool(valuePool) {}
@@ -72,8 +99,10 @@
// 'status' would be initialized to {@code VehiclePropertyStatus::AVAILABLE}, if this is to
// override an existing value, the status for the existing value would be used for the
// overridden value.
+ // 'EventMode' controls whether the 'OnValueChangeCallback' will be called for this operation.
VhalResult<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
- bool updateStatus = false);
+ bool updateStatus = false,
+ EventMode mode = EventMode::ON_VALUE_CHANGE);
// Remove a given property value from the property store. The 'propValue' would be used to
// generate the key for the value to remove.
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
index 8521c4d..2eca6b7 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
@@ -48,7 +48,7 @@
std::scoped_lock<std::mutex> lockGuard(mLock);
// Aligns the nextTime to multiply of interval.
- int64_t nextTime = ceil(elapsedRealtimeNano() / intervalInNano) * intervalInNano;
+ int64_t nextTime = ceil(uptimeNanos() / intervalInNano) * intervalInNano;
std::unique_ptr<CallbackInfo> info = std::make_unique<CallbackInfo>();
info->callback = callback;
@@ -128,7 +128,7 @@
}
// The first element is the nearest next event.
int64_t nextTime = mCallbackQueue[0]->nextTime;
- int64_t now = elapsedRealtimeNano();
+ int64_t now = uptimeNanos();
if (nextTime > now) {
interval = nextTime - now;
} else {
@@ -146,7 +146,7 @@
{
ScopedLockAssertion lockAssertion(mLock);
- int64_t now = elapsedRealtimeNano();
+ int64_t now = uptimeNanos();
while (mCallbackQueue.size() > 0) {
int64_t nextTime = mCallbackQueue[0]->nextTime;
if (nextTime > now) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index c8fb994..646dc0e 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -106,7 +106,8 @@
}
VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
- bool updateStatus) {
+ bool updateStatus,
+ VehiclePropertyStore::EventMode eventMode) {
std::scoped_lock<std::mutex> g(mLock);
int32_t propId = propValue->prop;
@@ -145,7 +146,12 @@
}
record->values[recId] = std::move(propValue);
- if (valueUpdated && mOnValueChangeCallback != nullptr) {
+
+ if (eventMode == EventMode::NEVER) {
+ return {};
+ }
+
+ if ((eventMode == EventMode::ALWAYS || valueUpdated) && mOnValueChangeCallback != nullptr) {
mOnValueChangeCallback(*(record->values[recId]));
}
return {};
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index 4d6f811..fea5034 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -448,6 +448,67 @@
ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
}
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNoUpdateForTimestampChange) {
+ VehiclePropValue updatedValue{
+ .prop = INVALID_PROP_ID,
+ };
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ mStore->setOnValueChangeCallback(
+ [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+ // Write the same value with different timestamp should succeed but should not trigger callback.
+ fuelCapacity.timestamp = 1;
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackForceUpdate) {
+ VehiclePropValue updatedValue{
+ .prop = INVALID_PROP_ID,
+ };
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ mStore->setOnValueChangeCallback(
+ [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+ fuelCapacity.timestamp = 1;
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), /*updateStatus=*/false,
+ VehiclePropertyStore::EventMode::ALWAYS));
+
+ ASSERT_EQ(updatedValue, fuelCapacity);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackForceNoUpdate) {
+ VehiclePropValue updatedValue{
+ .prop = INVALID_PROP_ID,
+ };
+ VehiclePropValue fuelCapacity = {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .value = {.floatValues = {1.0}},
+ };
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+ mStore->setOnValueChangeCallback(
+ [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+ fuelCapacity.value.floatValues[0] = 2.0;
+ fuelCapacity.timestamp = 1;
+
+ ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), /*updateStatus=*/false,
+ VehiclePropertyStore::EventMode::NEVER));
+
+ ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
index 57705bc..f940000 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
@@ -279,8 +279,10 @@
* with specified torchStrength if the torch is OFF.
*
* The torchStrength value must be within the valid range i.e. >=1 and
- * <= FLASH_INFO_STRENGTH_MAXIMUM_LEVEL. Whenever the torch is turned OFF,
- * the brightness level will reset to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
+ * <= FLASH_INFO_STRENGTH_MAXIMUM_LEVEL. The FLASH_INFO_STRENGTH_MAXIMUM_LEVEL must
+ * be set to a level which will not cause any burn out issues. Whenever
+ * the torch is turned OFF, the brightness level will reset to
+ * FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
* When the client calls setTorchMode(ON) after turnOnTorchWithStrengthLevel(N),
* the flash unit will have brightness level equal to N. This level does not
* represent the real brightness units. It is linear in nature i.e. flashlight
diff --git a/cas/aidl/Android.bp b/cas/aidl/Android.bp
new file mode 100644
index 0000000..32f12b1
--- /dev/null
+++ b/cas/aidl/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.cas",
+ vendor_available: true,
+ srcs: ["android/hardware/cas/*.aidl"],
+ stability: "vintf",
+ imports: ["android.hardware.common-V2"],
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
new file mode 100644
index 0000000..7b8099f
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable AidlCasPluginDescriptor {
+ int caSystemId;
+ String name;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
new file mode 100644
index 0000000..dd355af
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+union DestinationBuffer {
+ android.hardware.cas.SharedBuffer nonsecureMemory;
+ android.hardware.common.NativeHandle secureMemory;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
new file mode 100644
index 0000000..e169beb
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface ICas {
+ void closeSession(in byte[] sessionId);
+ byte[] openSession(in android.hardware.cas.SessionIntent intent, in android.hardware.cas.ScramblingMode mode);
+ void processEcm(in byte[] sessionId, in byte[] ecm);
+ void processEmm(in byte[] emm);
+ void provision(in String provisionString);
+ void refreshEntitlements(in int refreshType, in byte[] refreshData);
+ void release();
+ void sendEvent(in int event, in int arg, in byte[] eventData);
+ void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
+ void setPrivateData(in byte[] pvtData);
+ void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
new file mode 100644
index 0000000..ebc13ce
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface ICasListener {
+ void onEvent(in int event, in int arg, in byte[] data);
+ void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
+ void onStatusUpdate(in android.hardware.cas.StatusEvent event, in int number);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
new file mode 100644
index 0000000..9bf7903
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface IDescrambler {
+ int descramble(in android.hardware.cas.ScramblingControl scramblingControl, in android.hardware.cas.SubSample[] subSamples, in android.hardware.cas.SharedBuffer srcBuffer, in long srcOffset, in android.hardware.cas.DestinationBuffer dstBuffer, in long dstOffset);
+ void release();
+ boolean requiresSecureDecoderComponent(in String mime);
+ void setMediaCasSession(in byte[] sessionId);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
new file mode 100644
index 0000000..f5c8018
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface IMediaCasService {
+ android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
+ android.hardware.cas.ICas createPlugin(in int CA_system_id, in android.hardware.cas.ICasListener listener);
+ android.hardware.cas.AidlCasPluginDescriptor[] enumeratePlugins();
+ boolean isDescramblerSupported(in int CA_system_id);
+ boolean isSystemIdSupported(in int CA_system_id);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
new file mode 100644
index 0000000..d71d4be
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="int") @VintfStability
+enum ScramblingControl {
+ UNSCRAMBLED = 0,
+ RESERVED = 1,
+ EVENKEY = 2,
+ ODDKEY = 3,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
new file mode 100644
index 0000000..e3923c7
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="int") @VintfStability
+enum ScramblingMode {
+ RESERVED = 0,
+ DVB_CSA1 = 1,
+ DVB_CSA2 = 2,
+ DVB_CSA3_STANDARD = 3,
+ DVB_CSA3_MINIMAL = 4,
+ DVB_CSA3_ENHANCE = 5,
+ DVB_CISSA_V1 = 6,
+ DVB_IDSA = 7,
+ MULTI2 = 8,
+ AES128 = 9,
+ AES_CBC = 10,
+ AES_ECB = 11,
+ AES_SCTE52 = 12,
+ TDES_ECB = 13,
+ TDES_SCTE52 = 14,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
new file mode 100644
index 0000000..af95f80
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="int") @VintfStability
+enum SessionIntent {
+ LIVE = 0,
+ PLAYBACK = 1,
+ RECORD = 2,
+ TIMESHIFT = 3,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
new file mode 100644
index 0000000..a18aa57
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable SharedBuffer {
+ android.hardware.common.Ashmem heapBase;
+ long offset;
+ long size;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
new file mode 100644
index 0000000..3d3a8a0
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable Status {
+ const int OK = 0;
+ const int ERROR_CAS_NO_LICENSE = -1;
+ const int ERROR_CAS_LICENSE_EXPIRED = -2;
+ const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+ const int ERROR_CAS_CANNOT_HANDLE = -4;
+ const int ERROR_CAS_INVALID_STATE = -5;
+ const int BAD_VALUE = -6;
+ const int ERROR_CAS_NOT_PROVISIONED = -7;
+ const int ERROR_CAS_RESOURCE_BUSY = -8;
+ const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+ const int ERROR_CAS_TAMPER_DETECTED = -10;
+ const int ERROR_CAS_DEVICE_REVOKED = -11;
+ const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+ const int ERROR_CAS_DECRYPT = -13;
+ const int ERROR_CAS_UNKNOWN = -14;
+ const int ERROR_CAS_NEED_ACTIVATION = -15;
+ const int ERROR_CAS_NEED_PAIRING = -16;
+ const int ERROR_CAS_NO_CARD = -17;
+ const int ERROR_CAS_CARD_MUTE = -18;
+ const int ERROR_CAS_CARD_INVALID = -19;
+ const int ERROR_CAS_BLACKOUT = -20;
+ const int ERROR_CAS_REBOOTING = -21;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
new file mode 100644
index 0000000..178cabc
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="byte") @VintfStability
+enum StatusEvent {
+ PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
+ PLUGIN_SESSION_NUMBER_CHANGED = 1,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
new file mode 100644
index 0000000..d9ee3b4
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable SubSample {
+ int numBytesOfClearData;
+ int numBytesOfEncryptedData;
+}
diff --git a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
new file mode 100644
index 0000000..55b328a
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * Describes a CAS plugin with its system ID and name.
+ */
+@VintfStability
+parcelable AidlCasPluginDescriptor {
+ int caSystemId;
+ String name;
+}
diff --git a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
new file mode 100644
index 0000000..068f29d
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.SharedBuffer;
+import android.hardware.common.NativeHandle;
+
+@VintfStability
+union DestinationBuffer {
+ /**
+ * If type == SHARED_MEMORY, the descrambled data must be written
+ * to user-space non-secure shared memory.
+ */
+ SharedBuffer nonsecureMemory;
+
+ /**
+ * If type == NATIVE_HANDLE, the descrambled data must be written
+ * to secure memory referenced by the vendor's buffer allocator.
+ */
+ NativeHandle secureMemory;
+}
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
new file mode 100644
index 0000000..4c938c7
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.ScramblingMode;
+import android.hardware.cas.SessionIntent;
+
+/**
+ * ICas is the API to control the CAS. It is used to manage sessions, provision/refresh the cas
+ * system, and process the EMM/ECM messages. It also allows bi-directional, scheme-specific
+ * communications between the client and the cas system.
+ */
+@VintfStability
+interface ICas {
+ /**
+ * Close a session.
+ *
+ * @param sessionId The id of the session to be closed.
+ */
+ void closeSession(in byte[] sessionId);
+
+ /**
+ * Open a session to descramble one or more streams by specifying intention
+ * and scrambling mode.
+ *
+ * @param intent the intention of the session to be opened.
+ * @param mode the scrambling mode the session will use.
+ *
+ * @return sessionId The id of the newly opened session.
+ */
+ byte[] openSession(in SessionIntent intent, in ScramblingMode mode);
+
+ /**
+ * Process an ECM from the ECM stream for this session’s elementary stream.
+ *
+ * @param sessionId the id of the session which the ecm data applies to.
+ * @param ecm a byte array containing the ecm data.
+ */
+ void processEcm(in byte[] sessionId, in byte[] ecm);
+
+ /**
+ * Process an in-band EMM from the EMM stream.
+ *
+ * @param emm a byte array containing the emm data.
+ */
+ void processEmm(in byte[] emm);
+
+ /**
+ * Initiate a provisioning operation for a CA system.
+ *
+ * @param provisionString string containing information needed for the
+ * provisioning operation, the format of which is scheme and implementation
+ * specific.
+ */
+ void provision(in String provisionString);
+
+ /**
+ * Notify the CA system to refresh entitlement keys.
+ *
+ * @param refreshType the type of the refreshment.
+ * @param refreshData private data associated with the refreshment.
+ */
+ void refreshEntitlements(in int refreshType, in byte[] refreshData);
+
+ /**
+ * Release the descrambler instance.
+ */
+ void release();
+
+ /**
+ * Send an scheme-specific event to the CasPlugin.
+ *
+ * @param event an integer denoting a scheme-specific event to be sent.
+ * @param arg a scheme-specific integer argument for the event.
+ * @param data a byte array containing scheme-specific data for the event.
+ */
+ void sendEvent(in int event, in int arg, in byte[] eventData);
+
+ /**
+ * Send an scheme-specific session event to the CasPlugin.
+ *
+ * @param sessionId the id of an opened session.
+ * @param event an integer denoting a scheme-specific event to be sent.
+ * @param arg a scheme-specific integer argument for the event.
+ * @param data a byte array containing scheme-specific data for the event.
+ */
+ void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
+
+ /**
+ * Provide the CA private data from a CA_descriptor in the conditional
+ * access table to a CasPlugin.
+ *
+ * @param pvtData a byte array containing the private data, the format of
+ * which is scheme-specific and opaque to the framework.
+ */
+ void setPrivateData(in byte[] pvtData);
+
+ /**
+ * Provide the CA private data from a CA_descriptor in the program map
+ * table to a session.
+ *
+ * @param sessionId the id of the session which the private data applies to.
+ * @param pvtData a byte array containing the private data, the format of
+ * which is scheme-specific and opaque to the framework.
+ */
+ void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+}
diff --git a/cas/aidl/android/hardware/cas/ICasListener.aidl b/cas/aidl/android/hardware/cas/ICasListener.aidl
new file mode 100644
index 0000000..32d843f
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ICasListener.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.StatusEvent;
+
+@VintfStability
+interface ICasListener {
+ /**
+ * Notify the listener of a scheme-specific event from the CA system.
+ *
+ * @param event an integer whose meaning is scheme-specific.
+ * @param arg an integer whose meaning is scheme-specific.
+ * @param data a byte array of data whose format and meaning are
+ * scheme-specific.
+ */
+ void onEvent(in int event, in int arg, in byte[] data);
+
+ /**
+ * Notify the listener of a scheme-specific session event from CA system.
+ *
+ * @param sessionId the id of an opened session.
+ * @param event an integer whose meaning is scheme-specific.
+ * @param arg an integer whose meaning is scheme-specific.
+ * @param data a byte array of data whose format and meaning are
+ * scheme-specific.
+ */
+ void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
+
+ /**
+ * Notify the listener that the status of CAS system has changed.
+ *
+ * @param event the event type of status change.
+ * @param number value for status event.
+ * For PLUGIN_PHYSICAL_MODULE_CHANGED event:
+ * the positive number presents how many plugins are inserted;
+ * the negative number presents how many plugins are removed.
+ * Client must enumerate plugins after receive the event.
+ * For PLUGIN_SESSION_NUMBER_CHANGED event:
+ * the number presents how many sessions are supported
+ * in the plugin.
+ */
+ void onStatusUpdate(in StatusEvent event, in int number);
+}
diff --git a/cas/aidl/android/hardware/cas/IDescrambler.aidl b/cas/aidl/android/hardware/cas/IDescrambler.aidl
new file mode 100644
index 0000000..33fbe75
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/IDescrambler.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.DestinationBuffer;
+import android.hardware.cas.ScramblingControl;
+import android.hardware.cas.SharedBuffer;
+import android.hardware.cas.SubSample;
+
+/**
+ * IDescrambler is the API to control the descrambling operations.
+ */
+@VintfStability
+interface IDescrambler {
+ /**
+ * Descramble the data in a source SharedBuffer, described by an array of
+ * SubSample structures.
+ *
+ * @param scramblingControl an enumeration indicating the key that the subsamples
+ * were scrambled with.
+ * @param subSamples an array of SubSample structures describing the number of
+ * clear and scrambled bytes within each subsample.
+ * @param srcBuffer the SharedBuffer containing the source scrambled data.
+ * @param srcOffset the position where the source scrambled data starts at.
+ * @param dstBuffer the DestinationBuffer to hold the descrambled data.
+ * @param dstOffset the position where the descrambled data should start at.
+ *
+ * @return bytesWritten Number of bytes that have been successfully written.
+ */
+ int descramble(in ScramblingControl scramblingControl, in SubSample[] subSamples,
+ in SharedBuffer srcBuffer, in long srcOffset, in DestinationBuffer dstBuffer,
+ in long dstOffset);
+
+ /**
+ * Release the descrambler instance.
+ */
+ void release();
+
+ /**
+ * Query if the scrambling scheme requires the use of a secure decoder
+ * to decode data of the given mime type.
+ *
+ * @param mime the mime type of the media data.
+ * @return whether the descrambler requires a secure decoder.
+ */
+ boolean requiresSecureDecoderComponent(in String mime);
+
+ /**
+ * Associate a MediaCas session with this MediaDescrambler instance.
+ *
+ * @param sessionId the id of the session to associate with this descrambler instance.
+ */
+ void setMediaCasSession(in byte[] sessionId);
+}
diff --git a/cas/aidl/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
new file mode 100644
index 0000000..8bc31f6
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.AidlCasPluginDescriptor;
+import android.hardware.cas.ICas;
+import android.hardware.cas.ICasListener;
+import android.hardware.cas.IDescrambler;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ */
+@VintfStability
+interface IMediaCasService {
+ /**
+ * Construct a new instance of a DescramblerPlugin given a CA_system_id.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @return the newly created plugin interface.
+ */
+ IDescrambler createDescrambler(in int CA_system_id);
+
+ /**
+ * Construct a new instance of a CasPlugin given a CA_system_id.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @param listener the event listener to receive events coming from the CasPlugin.
+ * @return the newly created CasPlugin interface.
+ */
+ ICas createPlugin(in int CA_system_id, in ICasListener listener);
+
+ /**
+ * List all available CA systems on the device.
+ *
+ * @return an array of descriptors for the available CA systems.
+ */
+ AidlCasPluginDescriptor[] enumeratePlugins();
+
+ /**
+ * Query if the descrambling scheme for a CA system is supported on this device.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @return whether the specified descrambling scheme is supported on this device.
+ */
+ boolean isDescramblerSupported(in int CA_system_id);
+
+ /**
+ * Query if a certain CA system is supported on this device.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @return whether the specified CA system is supported on this device.
+ */
+ boolean isSystemIdSupported(in int CA_system_id);
+}
diff --git a/cas/aidl/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
new file mode 100644
index 0000000..b36787c
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * Enumerates the keys used to scramble the content.
+ */
+@VintfStability
+@Backing(type="int")
+enum ScramblingControl {
+ UNSCRAMBLED = 0,
+ RESERVED = 1,
+ EVENKEY = 2,
+ ODDKEY = 3,
+}
diff --git a/cas/aidl/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
new file mode 100644
index 0000000..9d73eba
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The Scrambling Mode.
+ */
+@VintfStability
+@Backing(type="int")
+enum ScramblingMode {
+ RESERVED = 0,
+
+ /**
+ * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
+ * the default mode and shall be used when the scrambling descriptor
+ * is not present in the program map section. DVB scrambling mode is
+ * specified in ETSI EN 300 468 specification.
+ */
+ DVB_CSA1,
+
+ DVB_CSA2,
+
+ /**
+ * DVB-CSA3 in standard mode.
+ */
+ DVB_CSA3_STANDARD,
+
+ /**
+ * DVB-CSA3 in minimally enhanced mode.
+ */
+ DVB_CSA3_MINIMAL,
+
+ /**
+ * DVB-CSA3 in fully enhanced mode.
+ */
+ DVB_CSA3_ENHANCE,
+
+ /**
+ * DVB-CISSA version 1.
+ */
+ DVB_CISSA_V1,
+
+ /**
+ * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
+ */
+ DVB_IDSA,
+
+ /**
+ * a symmetric key algorithm.
+ */
+ MULTI2,
+
+ /**
+ * Advanced Encryption System (AES) 128-bit Encryption mode.
+ */
+ AES128,
+
+ /**
+ * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
+ */
+ AES_CBC,
+
+ /**
+ * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
+ */
+ AES_ECB,
+
+ /**
+ * Advanced Encryption System (AES) Society of Cable Telecommunications
+ * Engineers (SCTE) 52 mode.
+ */
+ AES_SCTE52,
+
+ /**
+ * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
+ */
+ TDES_ECB,
+
+ /**
+ * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
+ * Engineers (SCTE) 52 mode.
+ */
+ TDES_SCTE52,
+}
diff --git a/cas/aidl/android/hardware/cas/SessionIntent.aidl b/cas/aidl/android/hardware/cas/SessionIntent.aidl
new file mode 100644
index 0000000..844deab
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SessionIntent.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The intented usage for the session.
+ */
+@VintfStability
+@Backing(type="int")
+enum SessionIntent {
+ /**
+ * Live Stream.
+ */
+ LIVE,
+
+ /**
+ * Playback Recorded Stream.
+ */
+ PLAYBACK,
+
+ /**
+ * Record Live Stream.
+ */
+ RECORD,
+
+ /**
+ * View the content with Time Shift capability
+ */
+ TIMESHIFT,
+}
diff --git a/cas/aidl/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
new file mode 100644
index 0000000..8a94ff7
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.common.Ashmem;
+
+/**
+ * SharedBuffer describes a shared buffer which is defined by a heapBase, an
+ * offset and a size. The offset is relative to the shared memory base for the
+ * memory region identified by heapBase.
+ */
+@VintfStability
+parcelable SharedBuffer {
+ /**
+ * Ashmem shared memory
+ */
+ Ashmem heapBase;
+
+ /**
+ * The offset from the shared memory base
+ */
+ long offset;
+
+ /**
+ * The size of the shared buffer in bytes
+ */
+ long size;
+}
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
new file mode 100644
index 0000000..b2be34b
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+@VintfStability
+parcelable Status {
+ /**
+ * The CAS plugin must return OK when an operation completes without any
+ * errors.
+ */
+ const int OK = 0;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is
+ * attempted and no license keys have been provided.
+ */
+ const int ERROR_CAS_NO_LICENSE = -1;
+
+ /**
+ * ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made
+ * to use a license and the keys in that license have expired.
+ */
+ const int ERROR_CAS_LICENSE_EXPIRED = -2;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an
+ * attempt is made to use a session that has not been opened.
+ */
+ const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported
+ * data format or operation is attempted.
+ */
+ const int ERROR_CAS_CANNOT_HANDLE = -4;
+
+ /**
+ * ERROR_CAS_INVALID_STATE must be returned when the device is in a state
+ * where it is not able to perform descrambling.
+ */
+ const int ERROR_CAS_INVALID_STATE = -5;
+
+ /**
+ * The CAS plugin must return BAD_VALUE whenever an illegal parameter is
+ * passed to one of the interface functions.
+ */
+ const int BAD_VALUE = -6;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device
+ * has not yet been provisioned.
+ */
+ const int ERROR_CAS_NOT_PROVISIONED = -7;
+
+ /**
+ * ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS
+ * sessions or secure buffers are not available to perform a requested
+ * operation because they are already in use.
+ */
+ const int ERROR_CAS_RESOURCE_BUSY = -8;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION
+ * when the output protection level enabled on the device is not
+ * sufficient to meet the requirements in the license policy. HDCP is an
+ * example of a form of output protection.
+ */
+ const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to
+ * tamper with the CAS system is detected.
+ */
+ const int ERROR_CAS_TAMPER_DETECTED = -10;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response
+ * indicates that the device has been revoked. Device revocation means
+ * that the device is no longer permitted to play content.
+ */
+ const int ERROR_CAS_DEVICE_REVOKED = -11;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when
+ * descrambling is failing because the session is not initialized properly.
+ */
+ const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's
+ * descramble operation fails.
+ */
+ const int ERROR_CAS_DECRYPT = -13;
+
+ /**
+ * ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no
+ * other defined error is appropriate.
+ */
+ const int ERROR_CAS_UNKNOWN = -14;
+
+ /**
+ * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
+ */
+ const int ERROR_CAS_NEED_ACTIVATION = -15;
+
+ /**
+ * ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
+ */
+ const int ERROR_CAS_NEED_PAIRING = -16;
+
+ /**
+ * ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
+ */
+ const int ERROR_CAS_NO_CARD = -17;
+
+ /**
+ * ERROR_CAS_CARD_MUTE is used to report smart card is muted for
+ * descrambling.
+ */
+ const int ERROR_CAS_CARD_MUTE = -18;
+
+ /**
+ * ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
+ */
+ const int ERROR_CAS_CARD_INVALID = -19;
+
+ /**
+ * ERROR_CAS_BLACKOUT is used to report geographical blackout.
+ */
+ const int ERROR_CAS_BLACKOUT = -20;
+
+ /**
+ * ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
+ */
+ const int ERROR_CAS_REBOOTING = -21;
+}
diff --git a/cas/aidl/android/hardware/cas/StatusEvent.aidl b/cas/aidl/android/hardware/cas/StatusEvent.aidl
new file mode 100644
index 0000000..0f62634
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/StatusEvent.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The Event Type for status change.
+ */
+@VintfStability
+@Backing(type="byte")
+enum StatusEvent {
+ /**
+ * The status of CAS plugin was changed due to physical module insertion or
+ * removal. Client must call enumeratePlugins to update plugins' status.
+ */
+ PLUGIN_PHYSICAL_MODULE_CHANGED,
+
+ /**
+ * The status of supported session number was changed due to physical module
+ * insertion or removal. Client must update session resource according to
+ * latest StatusMessage from the StatusEvent. The plugin supports unlimited
+ * session by default.
+ */
+ PLUGIN_SESSION_NUMBER_CHANGED,
+}
diff --git a/cas/aidl/android/hardware/cas/SubSample.aidl b/cas/aidl/android/hardware/cas/SubSample.aidl
new file mode 100644
index 0000000..c1353cb
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SubSample.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * A subsample consists of some number of bytes of clear (unscrambled)
+ * data followed by a number of bytes of scrambled data.
+ */
+@VintfStability
+parcelable SubSample {
+ int numBytesOfClearData;
+ int numBytesOfEncryptedData;
+}
diff --git a/cas/aidl/default/Android.bp b/cas/aidl/default/Android.bp
new file mode 100755
index 0000000..3c16d57
--- /dev/null
+++ b/cas/aidl/default/Android.bp
@@ -0,0 +1,93 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "libcasexampleimpl",
+ vendor_available: true,
+
+ srcs: [
+ "CasImpl.cpp",
+ "DescramblerImpl.cpp",
+ "MediaCasService.cpp",
+ "SharedLibrary.cpp",
+ "TypeConvert.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.cas-V1-ndk",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ "media_plugin_headers",
+ ],
+}
+
+cc_defaults {
+ name: "cas_service_example_defaults",
+ vendor: true,
+ relative_install_path: "hw",
+
+ srcs: ["service.cpp"],
+
+ static_libs: [
+ "libaidlcommonsupport",
+ "libcasexampleimpl",
+ ],
+ shared_libs: [
+ "android.hardware.cas-V1-ndk",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ header_libs: ["media_plugin_headers"],
+ vintf_fragments: ["android.hardware.cas-service.xml"],
+}
+
+cc_binary {
+ name: "android.hardware.cas-service.example",
+ defaults: ["cas_service_example_defaults"],
+ init_rc: ["cas-default.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.cas-service.example-lazy",
+ defaults: ["cas_service_example_defaults"],
+ init_rc: ["cas-default-lazy.rc"],
+ cflags: ["-DLAZY_SERVICE"],
+}
+
+cc_fuzz {
+ name: "android.hardware.cas-service_fuzzer",
+ vendor: true,
+
+ defaults: ["service_fuzzer_defaults"],
+ srcs: ["fuzzer.cpp"],
+
+ shared_libs: [
+ "android.hardware.cas-V1-ndk",
+ "libcutils",
+ "liblog",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libcasexampleimpl",
+ ],
+ header_libs: ["media_plugin_headers"],
+ fuzz_config: {
+ componentid: 1344,
+ },
+}
diff --git a/cas/aidl/default/CasImpl.cpp b/cas/aidl/default/CasImpl.cpp
new file mode 100755
index 0000000..2d31b35
--- /dev/null
+++ b/cas/aidl/default/CasImpl.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ icensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-CasImpl"
+
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+CasImpl::CasImpl(const shared_ptr<ICasListener>& listener) : mListener(listener) {
+ ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+ ALOGV("DTOR");
+ release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+ const CasSessionId* sessionId) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+// static
+void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onStatusUpdate(event, arg);
+}
+
+void CasImpl::init(CasPlugin* plugin) {
+ shared_ptr<CasPlugin> holder(plugin);
+ atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ vector<uint8_t> eventData;
+ if (data != NULL) {
+ eventData.assign(data, data + size);
+ }
+
+ mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+ size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ vector<uint8_t> eventData;
+ if (data != NULL) {
+ eventData.assign(data, data + size);
+ }
+
+ if (sessionId != NULL) {
+ mListener->onSessionEvent(*sessionId, event, arg, eventData);
+ } else {
+ mListener->onEvent(event, arg, eventData);
+ }
+}
+
+void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
+ if (mListener == NULL) {
+ return;
+ }
+ mListener->onStatusUpdate(static_cast<StatusEvent>(event), arg);
+}
+
+ScopedAStatus CasImpl::setPluginStatusUpdateCallback() {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
+}
+
+ScopedAStatus CasImpl::setPrivateData(const vector<uint8_t>& pvtData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setPrivateData(pvtData));
+}
+
+ScopedAStatus CasImpl::openSession(SessionIntent intent, ScramblingMode mode,
+ vector<uint8_t>* sessionId) {
+ ALOGV("%s", __FUNCTION__);
+
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ status_t err = INVALID_OPERATION;
+ if (holder.get() != nullptr) {
+ err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
+ sessionId);
+ holder.reset();
+ }
+
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::setSessionPrivateData(const vector<uint8_t>& sessionId,
+ const vector<uint8_t>& pvtData) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+ScopedAStatus CasImpl::closeSession(const vector<uint8_t>& sessionId) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->closeSession(sessionId));
+}
+
+ScopedAStatus CasImpl::processEcm(const vector<uint8_t>& sessionId, const vector<uint8_t>& ecm) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+ScopedAStatus CasImpl::processEmm(const vector<uint8_t>& emm) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->processEmm(emm));
+}
+
+ScopedAStatus CasImpl::sendEvent(int32_t event, int32_t arg, const vector<uint8_t>& eventData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->sendEvent(event, arg, eventData);
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const vector<uint8_t>& eventData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::provision(const string& provisionString) {
+ ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+ScopedAStatus CasImpl::refreshEntitlements(int32_t refreshType,
+ const vector<uint8_t>& refreshData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->refreshEntitlements(refreshType, refreshData);
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::release() {
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ shared_ptr<CasPlugin> holder(nullptr);
+ atomic_store(&mPluginHolder, holder);
+
+ return ScopedAStatus::ok();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/CasImpl.h b/cas/aidl/default/CasImpl.h
new file mode 100755
index 0000000..84a8115
--- /dev/null
+++ b/cas/aidl/default/CasImpl.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/cas/BnCas.h>
+#include <aidl/android/hardware/cas/ICasListener.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class CasImpl : public BnCas {
+ public:
+ CasImpl(const shared_ptr<ICasListener>& listener);
+ virtual ~CasImpl();
+
+ static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+ static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+ const CasSessionId* sessionId);
+
+ static void StatusUpdate(void* appData, int32_t event, int32_t arg);
+
+ void init(CasPlugin* plugin);
+ void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+ void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+ size_t size);
+
+ void onStatusUpdate(int32_t event, int32_t arg);
+
+ // ICas inherits
+
+ ScopedAStatus setPluginStatusUpdateCallback();
+
+ virtual ScopedAStatus setPrivateData(const vector<uint8_t>& pvtData) override;
+
+ virtual ScopedAStatus openSession(SessionIntent intent, ScramblingMode mode,
+ vector<uint8_t>* sessionId) override;
+
+ virtual ScopedAStatus closeSession(const vector<uint8_t>& sessionId) override;
+
+ virtual ScopedAStatus setSessionPrivateData(const vector<uint8_t>& sessionId,
+ const vector<uint8_t>& pvtData) override;
+
+ virtual ScopedAStatus processEcm(const vector<uint8_t>& sessionId,
+ const vector<uint8_t>& ecm) override;
+
+ virtual ScopedAStatus processEmm(const vector<uint8_t>& emm) override;
+
+ virtual ScopedAStatus sendEvent(int32_t event, int32_t arg,
+ const vector<uint8_t>& eventData) override;
+
+ virtual ScopedAStatus sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const vector<uint8_t>& eventData) override;
+
+ virtual ScopedAStatus provision(const string& provisionString) override;
+
+ virtual ScopedAStatus refreshEntitlements(int32_t refreshType,
+ const vector<uint8_t>& refreshData) override;
+
+ virtual ScopedAStatus release() override;
+
+ private:
+ struct PluginHolder;
+ shared_ptr<CasPlugin> mPluginHolder;
+ shared_ptr<ICasListener> mListener;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/DescramblerImpl.cpp b/cas/aidl/default/DescramblerImpl.cpp
new file mode 100755
index 0000000..a96fd46
--- /dev/null
+++ b/cas/aidl/default/DescramblerImpl.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-DescramblerImpl"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <inttypes.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+#define CHECK_SUBSAMPLE_DEF(type) \
+ static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+ static_assert(offsetof(SubSample, numBytesOfClearData) == \
+ offsetof(type::SubSample, mNumBytesOfClearData), \
+ "SubSample: numBytesOfClearData offset doesn't match"); \
+ static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \
+ offsetof(type::SubSample, mNumBytesOfEncryptedData), \
+ "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(DescramblerPlugin* plugin) : mPluginHolder(plugin) {
+ ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+ ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+ release();
+}
+
+ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).string());
+
+ shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->setMediaCasSession(in_sessionId));
+}
+
+ScopedAStatus DescramblerImpl::requiresSecureDecoderComponent(const string& in_mime,
+ bool* _aidl_return) {
+ shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ *_aidl_return = false;
+ }
+
+ *_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
+ return ScopedAStatus::ok();
+}
+
+static inline bool validateRangeForSize(int64_t offset, int64_t length, int64_t size) {
+ return isInRange<int64_t, uint64_t>(0, (uint64_t)size, offset, (uint64_t)length);
+}
+
+ScopedAStatus DescramblerImpl::descramble(ScramblingControl scramblingControl,
+ const vector<SubSample>& subSamples,
+ const SharedBuffer& srcBuffer, int64_t srcOffset,
+ const DestinationBuffer& dstBuffer, int64_t dstOffset,
+ int32_t* _aidl_return) {
+ ALOGV("%s", __FUNCTION__);
+
+ // heapbase's size is stored in int64_t, but mapMemory's mmap will map size in
+ // size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed but the
+ // mapped memory's actual size will be smaller than the reported size.
+ if (srcBuffer.heapBase.size > SIZE_MAX) {
+ ALOGE("Invalid memory size: %" PRIu64 "", srcBuffer.heapBase.size);
+ android_errorWriteLog(0x534e4554, "79376389");
+ return toStatus(BAD_VALUE);
+ }
+
+ void* srcPtr = mmap(NULL, srcBuffer.heapBase.size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ srcBuffer.heapBase.fd.get(), 0);
+
+ // Validate if the offset and size in the SharedBuffer is consistent with the
+ // mapped heapbase, since the offset and size is controlled by client.
+ if (srcPtr == NULL) {
+ ALOGE("Failed to map src buffer.");
+ return toStatus(BAD_VALUE);
+ }
+ if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size)) {
+ ALOGE("Invalid src buffer range: offset %" PRIu64 ", size %" PRIu64
+ ", srcMem"
+ "size %" PRIu64 "",
+ srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ return toStatus(BAD_VALUE);
+ }
+
+ // use 64-bit here to catch bad subsample size that might be overflowing.
+ uint64_t totalBytesInSubSamples = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
+ uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
+ totalBytesInSubSamples += (uint64_t)numBytesOfClearData + numBytesOfEncryptedData;
+ }
+ // Further validate if the specified srcOffset and requested total subsample size
+ // is consistent with the source shared buffer size.
+ if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+ ALOGE("Invalid srcOffset and subsample size: "
+ "srcOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
+ ", srcBuffer"
+ "size %" PRIu64 "",
+ srcOffset, totalBytesInSubSamples, srcBuffer.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ return toStatus(BAD_VALUE);
+ }
+ srcPtr = (uint8_t*)srcPtr + srcBuffer.offset;
+
+ void* dstPtr = NULL;
+ if (dstBuffer.getTag() == DestinationBuffer::Tag::nonsecureMemory) {
+ // When using shared memory, src buffer is also used as dst,
+ // we don't map it again here.
+ dstPtr = srcPtr;
+
+ // In this case the dst and src would be the same buffer, need to validate
+ // dstOffset against the buffer size too.
+ if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+ ALOGE("Invalid dstOffset and subsample size: "
+ "dstOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
+ ", srcBuffer"
+ "size %" PRIu64 "",
+ dstOffset, totalBytesInSubSamples, srcBuffer.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ return toStatus(BAD_VALUE);
+ }
+ } else {
+ native_handle_t* handle = makeFromAidl(dstBuffer.get<DestinationBuffer::secureMemory>());
+ dstPtr = static_cast<void*>(handle);
+ }
+
+ // Get a local copy of the shared_ptr for the plugin. Note that before
+ // calling the callback, this shared_ptr must be manually reset, since
+ // the client side could proceed as soon as the callback is called
+ // without waiting for this method to go out of scope.
+ shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ // Casting SubSample to DescramblerPlugin::SubSample, but need to ensure
+ // structs are actually identical
+
+ auto returnStatus =
+ holder->descramble(dstBuffer.getTag() != DestinationBuffer::Tag::nonsecureMemory,
+ (DescramblerPlugin::ScramblingControl)scramblingControl,
+ subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+ srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+ holder.reset();
+ *_aidl_return = returnStatus;
+ return toStatus(returnStatus >= 0 ? OK : returnStatus);
+}
+
+ScopedAStatus DescramblerImpl::release() {
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ shared_ptr<DescramblerPlugin> holder(nullptr);
+ atomic_store(&mPluginHolder, holder);
+
+ return ScopedAStatus::ok();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/DescramblerImpl.h b/cas/aidl/default/DescramblerImpl.h
new file mode 100755
index 0000000..2efc1a0
--- /dev/null
+++ b/cas/aidl/default/DescramblerImpl.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/cas/BnDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class DescramblerImpl : public BnDescrambler {
+ public:
+ DescramblerImpl(DescramblerPlugin* plugin);
+ virtual ~DescramblerImpl();
+
+ virtual ScopedAStatus setMediaCasSession(const vector<uint8_t>& in_sessionId) override;
+
+ virtual ScopedAStatus requiresSecureDecoderComponent(const string& in_mime,
+ bool* _aidl_return) override;
+
+ virtual ScopedAStatus descramble(ScramblingControl in_scramblingControl,
+ const vector<SubSample>& in_subSamples,
+ const SharedBuffer& in_srcBuffer, int64_t in_srcOffset,
+ const DestinationBuffer& in_dstBuffer, int64_t in_dstOffset,
+ int32_t* _aidl_return) override;
+
+ virtual ScopedAStatus release() override;
+
+ private:
+ shared_ptr<DescramblerPlugin> mPluginHolder;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/FactoryLoader.h b/cas/aidl/default/FactoryLoader.h
new file mode 100755
index 0000000..f90b109
--- /dev/null
+++ b/cas/aidl/default/FactoryLoader.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 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 <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+
+template <class T>
+class FactoryLoader {
+ public:
+ FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+ virtual ~FactoryLoader() { closeFactory(); }
+
+ bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
+ T** factory = NULL);
+
+ bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
+
+ private:
+ typedef T* (*CreateFactoryFunc)();
+
+ Mutex mMapLock;
+ T* mFactory;
+ const char* mCreateFactoryFuncName;
+ shared_ptr<SharedLibrary> mLibrary;
+ KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+ KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
+
+ bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+ shared_ptr<SharedLibrary>* library, T** factory);
+
+ bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
+
+ bool openFactory(const String8& path);
+ void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
+ shared_ptr<SharedLibrary>* library, T** factory) {
+ if (library != NULL) {
+ library->reset();
+ }
+ if (factory != NULL) {
+ *factory = NULL;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ // first check cache
+ ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+ if (index >= 0) {
+ return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+ library, factory);
+ }
+
+ // no luck, have to search
+#ifdef __LP64__
+ String8 dirPath("/vendor/lib64/mediacas");
+#else
+ String8 dirPath("/vendor/lib/mediacas");
+#endif
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+ mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+ closedir(pDir);
+
+ return true;
+ }
+ }
+ }
+
+ closedir(pDir);
+
+ ALOGE("Failed to find plugin");
+ return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
+ ALOGI("enumeratePlugins");
+
+ results->clear();
+
+#ifdef __LP64__
+ String8 dirPath("/vendor/lib64/mediacas");
+#else
+ String8 dirPath("/vendor/lib/mediacas");
+#endif
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ queryPluginsFromPath(pluginPath, results);
+ }
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+ shared_ptr<SharedLibrary>* library,
+ T** factory) {
+ closeFactory();
+
+ if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+ closeFactory();
+ return false;
+ }
+
+ if (library != NULL) {
+ *library = mLibrary;
+ }
+ if (factory != NULL) {
+ *factory = mFactory;
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+ vector<AidlCasPluginDescriptor>* results) {
+ closeFactory();
+
+ vector<CasPluginDescriptor> descriptors;
+ if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+ closeFactory();
+ return false;
+ }
+
+ for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+ results->push_back(
+ AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+ // get strong pointer to open shared library
+ ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+ if (index >= 0) {
+ mLibrary = mLibraryPathToOpenLibraryMap[index];
+ } else {
+ index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+ }
+
+ if (!mLibrary.get()) {
+ mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
+ if (!*mLibrary) {
+ return false;
+ }
+
+ mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+ }
+
+ CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+ if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+ return false;
+ }
+ return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+ delete mFactory;
+ mFactory = NULL;
+ mLibrary.reset();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/MediaCasService.cpp b/cas/aidl/default/MediaCasService.cpp
new file mode 100755
index 0000000..8285613
--- /dev/null
+++ b/cas/aidl/default/MediaCasService.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-MediaCasService"
+
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+MediaCasService::MediaCasService()
+ : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+ScopedAStatus MediaCasService::enumeratePlugins(
+ vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) {
+ ALOGV("%s", __FUNCTION__);
+
+ mCasLoader.enumeratePlugins(aidlCasPluginDescriptors);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::isSystemIdSupported(int32_t CA_system_id, bool* _aidl_return) {
+ ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+ *_aidl_return = mCasLoader.findFactoryForScheme(CA_system_id);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::createPlugin(int32_t CA_system_id,
+ const shared_ptr<ICasListener>& listener,
+ shared_ptr<ICas>* _aidl_return) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+ if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
+
+ CasFactory* factory;
+ shared_ptr<SharedLibrary> library;
+ if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+ CasPlugin* plugin = NULL;
+ shared_ptr<CasImpl> casImpl = ::ndk::SharedRefBase::make<CasImpl>(listener);
+ if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+ OK &&
+ plugin != NULL) {
+ casImpl->init(plugin);
+ *_aidl_return = casImpl;
+ casImpl->setPluginStatusUpdateCallback();
+ }
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::isDescramblerSupported(int32_t CA_system_id, bool* _aidl_return) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+ *_aidl_return = mDescramblerLoader.findFactoryForScheme(CA_system_id);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::createDescrambler(int32_t CA_system_id,
+ shared_ptr<IDescrambler>* _aidl_return) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+ DescramblerFactory* factory;
+ shared_ptr<SharedLibrary> library;
+ if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+ DescramblerPlugin* plugin = NULL;
+ if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+ *_aidl_return = ::ndk::SharedRefBase::make<DescramblerImpl>(plugin);
+ }
+ }
+
+ return ScopedAStatus::ok();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/MediaCasService.h b/cas/aidl/default/MediaCasService.h
new file mode 100755
index 0000000..9662313
--- /dev/null
+++ b/cas/aidl/default/MediaCasService.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/android/hardware/cas/BnMediaCasService.h>
+#include <media/cas/DescramblerAPI.h>
+
+#include "FactoryLoader.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class MediaCasService : public BnMediaCasService {
+ public:
+ MediaCasService();
+
+ virtual ScopedAStatus enumeratePlugins(
+ vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) override;
+
+ virtual ScopedAStatus isSystemIdSupported(int32_t in_CA_system_id, bool* _aidl_return) override;
+
+ virtual ScopedAStatus createPlugin(int32_t in_CA_system_id,
+ const shared_ptr<ICasListener>& in_listener,
+ shared_ptr<ICas>* _aidl_return) override;
+
+ virtual ScopedAStatus isDescramblerSupported(int32_t in_CA_system_id,
+ bool* _aidl_return) override;
+
+ virtual ScopedAStatus createDescrambler(int32_t in_CA_system_id,
+ shared_ptr<IDescrambler>* _aidl_return) override;
+
+ private:
+ FactoryLoader<CasFactory> mCasLoader;
+ FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+ virtual ~MediaCasService();
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/OWNERS b/cas/aidl/default/OWNERS
new file mode 100755
index 0000000..4c55752
--- /dev/null
+++ b/cas/aidl/default/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1344
+quxiangfang@google.com
+hgchen@google.com
diff --git a/cas/aidl/default/SharedLibrary.cpp b/cas/aidl/default/SharedLibrary.cpp
new file mode 100755
index 0000000..e79f383
--- /dev/null
+++ b/cas/aidl/default/SharedLibrary.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <utils/Log.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+ mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+ if (mLibHandle != NULL) {
+ dlclose(mLibHandle);
+ mLibHandle = NULL;
+ }
+}
+
+bool SharedLibrary::operator!() const {
+ return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+ if (!mLibHandle) {
+ return NULL;
+ }
+ // Clear last error before we load the symbol again,
+ // in case the caller didn't retrieve it.
+ (void)dlerror();
+ return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+ const char* error = dlerror();
+ return error ? error : "No errors or unknown error";
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/SharedLibrary.h b/cas/aidl/default/SharedLibrary.h
new file mode 100755
index 0000000..d367866
--- /dev/null
+++ b/cas/aidl/default/SharedLibrary.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_interface_utils.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/String8.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+
+class SharedLibrary : public ndk::SharedRefBase {
+ public:
+ explicit SharedLibrary(const String8& path);
+ ~SharedLibrary();
+
+ bool operator!() const;
+ void* lookup(const char* symbol) const;
+ const char* lastError() const;
+
+ private:
+ void* mLibHandle;
+ DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/TypeConvert.cpp b/cas/aidl/default/TypeConvert.cpp
new file mode 100755
index 0000000..4f7005f
--- /dev/null
+++ b/cas/aidl/default/TypeConvert.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-TypeConvert"
+
+#include <aidl/android/hardware/cas/Status.h>
+#include <utils/Log.h>
+
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+ScopedAStatus toStatus(status_t legacyStatus) {
+ int status;
+ switch (legacyStatus) {
+ case OK:
+ return ndk::ScopedAStatus::ok();
+ case ERROR_CAS_NO_LICENSE:
+ status = Status::ERROR_CAS_NO_LICENSE;
+ break;
+ case ERROR_CAS_LICENSE_EXPIRED:
+ status = Status::ERROR_CAS_LICENSE_EXPIRED;
+ break;
+ case ERROR_CAS_SESSION_NOT_OPENED:
+ status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+ break;
+ case ERROR_CAS_CANNOT_HANDLE:
+ status = Status::ERROR_CAS_CANNOT_HANDLE;
+ break;
+ case ERROR_CAS_TAMPER_DETECTED:
+ status = Status::ERROR_CAS_INVALID_STATE;
+ break;
+ case BAD_VALUE:
+ status = Status::BAD_VALUE;
+ break;
+ case ERROR_CAS_NOT_PROVISIONED:
+ status = Status::ERROR_CAS_NOT_PROVISIONED;
+ break;
+ case ERROR_CAS_RESOURCE_BUSY:
+ status = Status::ERROR_CAS_RESOURCE_BUSY;
+ break;
+ case ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+ status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+ break;
+ case ERROR_CAS_DEVICE_REVOKED:
+ status = Status::ERROR_CAS_DEVICE_REVOKED;
+ break;
+ case ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+ status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+ break;
+ case ERROR_CAS_DECRYPT:
+ status = Status::ERROR_CAS_DECRYPT;
+ break;
+ case ERROR_CAS_NEED_ACTIVATION:
+ status = Status::ERROR_CAS_NEED_ACTIVATION;
+ break;
+ case ERROR_CAS_NEED_PAIRING:
+ status = Status::ERROR_CAS_NEED_PAIRING;
+ break;
+ case ERROR_CAS_NO_CARD:
+ status = Status::ERROR_CAS_NO_CARD;
+ break;
+ case ERROR_CAS_CARD_MUTE:
+ status = Status::ERROR_CAS_CARD_MUTE;
+ break;
+ case ERROR_CAS_CARD_INVALID:
+ status = Status::ERROR_CAS_CARD_INVALID;
+ break;
+ case ERROR_CAS_BLACKOUT:
+ status = Status::ERROR_CAS_BLACKOUT;
+ break;
+ default:
+ ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+ status = Status::ERROR_CAS_UNKNOWN;
+ break;
+ }
+ return ScopedAStatus::fromServiceSpecificError(status);
+}
+
+String8 sessionIdToString(const std::vector<uint8_t>& sessionId) {
+ String8 result;
+ for (auto it = sessionId.begin(); it != sessionId.end(); it++) {
+ result.appendFormat("%02x ", *it);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/TypeConvert.h b/cas/aidl/default/TypeConvert.h
new file mode 100755
index 0000000..ebfa286
--- /dev/null
+++ b/cas/aidl/default/TypeConvert.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_interface_utils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using ndk::ScopedAStatus;
+
+ScopedAStatus toStatus(status_t legacyStatus);
+
+String8 sessionIdToString(const std::vector<uint8_t>& sessionId);
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/android.hardware.cas-service.xml b/cas/aidl/default/android.hardware.cas-service.xml
new file mode 100755
index 0000000..6389fe2
--- /dev/null
+++ b/cas/aidl/default/android.hardware.cas-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.cas</name>
+ <fqname>IMediaCasService/default</fqname>
+ </hal>
+</manifest>
diff --git a/cas/aidl/default/cas-default-lazy.rc b/cas/aidl/default/cas-default-lazy.rc
new file mode 100755
index 0000000..60b59ca
--- /dev/null
+++ b/cas/aidl/default/cas-default-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.cas-default-lazy /vendor/bin/hw/android.hardware.cas-service.example-lazy
+ interface aidl android.hardware.cas.IMediaCasService/default
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ oneshot
+ disabled
diff --git a/cas/aidl/default/cas-default.rc b/cas/aidl/default/cas-default.rc
new file mode 100755
index 0000000..e00b9c5
--- /dev/null
+++ b/cas/aidl/default/cas-default.rc
@@ -0,0 +1,7 @@
+service vendor.cas-default /vendor/bin/hw/android.hardware.cas-service.example
+ interface aidl android.hardware.cas.IMediaCasService/default
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/fuzzer.cpp b/cas/aidl/default/fuzzer.cpp
new file mode 100755
index 0000000..db1369e
--- /dev/null
+++ b/cas/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 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 <MediaCasService.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using aidl::android::hardware::cas::MediaCasService;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto mediaCasServiceAidl = SharedRefBase::make<MediaCasService>();
+
+ fuzzService(mediaCasServiceAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/cas/aidl/default/service.cpp b/cas/aidl/default/service.cpp
new file mode 100755
index 0000000..bed2f01
--- /dev/null
+++ b/cas/aidl/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#define LOG_TAG "android.hardware.cas-service.example-lazy"
+#else
+const bool kLazyService = false;
+#define LOG_TAG "android.hardware.cas-service.example"
+#endif
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "MediaCasService.h"
+
+using aidl::android::hardware::cas::MediaCasService;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+ // Setup hwbinder service
+ std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
+
+ const std::string instance = std::string() + MediaCasService::descriptor + "/default";
+ binder_status_t status;
+
+ if (kLazyService) {
+ status = AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
+ } else {
+ status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ }
+ LOG_ALWAYS_FATAL_IF(status != STATUS_OK, "Error while registering cas service: %d", status);
+
+ ABinderProcess_joinThreadPool();
+ return 0;
+}
diff --git a/cas/aidl/vts/functional/Android.bp b/cas/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..295ae7c
--- /dev/null
+++ b/cas/aidl/vts/functional/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalCasAidlTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalCasAidlTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.cas-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
diff --git a/cas/aidl/vts/functional/OWNERS b/cas/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..4c55752
--- /dev/null
+++ b/cas/aidl/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1344
+quxiangfang@google.com
+hgchen@google.com
diff --git a/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
new file mode 100644
index 0000000..266b55d
--- /dev/null
+++ b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) 2022 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 "mediacas_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/cas/BnCasListener.h>
+#include <aidl/android/hardware/cas/IMediaCasService.h>
+#include <aidl/android/hardware/cas/Status.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <cutils/ashmem.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define INVALID_SYSTEM_ID 0
+#define WAIT_TIMEOUT 3000000000
+
+#define PROVISION_STR \
+ "{ " \
+ " \"id\": 21140844, " \
+ " \"name\": \"Test Title\", " \
+ " \"lowercase_organization_name\": \"Android\", " \
+ " \"asset_key\": { " \
+ " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \
+ " }, " \
+ " \"cas_type\": 1, " \
+ " \"track_types\": [ ] " \
+ "} "
+
+using aidl::android::hardware::common::Ashmem;
+using android::Mutex;
+using namespace aidl::android::hardware::cas;
+using namespace ndk;
+using namespace std;
+using namespace testing;
+
+const uint8_t kEcmBinaryBuffer[] = {
+ 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
+ 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
+ 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
+ 0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
+};
+
+const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
+
+const uint8_t kInBinaryBuffer[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+ 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+ 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+ 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+ 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+ 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+ 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+ 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+ 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+ 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
+ 0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
+ 0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
+ 0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
+ 0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
+ 0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
+ 0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
+ 0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
+ 0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
+ 0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
+ 0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
+ 0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
+ 0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
+ 0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
+ 0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
+ 0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
+ 0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
+ 0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
+ 0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
+ 0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
+ 0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
+ 0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
+ 0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
+ 0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
+ 0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
+ 0xc5, 0x4c, 0x24, 0x0e, 0x65,
+};
+
+const uint8_t kOutRefBinaryBuffer[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+ 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+ 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+ 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+ 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+ 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+ 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+ 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+ 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+ 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+ 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+ 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+ 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+ 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+ 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+ 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+ 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+ 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+ 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+ 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+ 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+ 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+ 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+ 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+ 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+ 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+ 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+ 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+ 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+ 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+ 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+ 0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+class MediaCasListener : public BnCasListener {
+ public:
+ virtual ScopedAStatus onEvent(int32_t event, int32_t arg,
+ const vector<uint8_t>& data) override {
+ Mutex::Autolock autoLock(mMsgLock);
+ mEvent = event;
+ mEventArg = arg;
+ mEventData = data;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return ScopedAStatus::ok();
+ }
+
+ virtual ScopedAStatus onSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const vector<uint8_t>& data) override {
+ Mutex::Autolock autoLock(mMsgLock);
+ mSessionId = sessionId;
+ mEvent = event;
+ mEventArg = arg;
+ mEventData = data;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return ScopedAStatus::ok();
+ }
+
+ virtual ScopedAStatus onStatusUpdate(StatusEvent event, int32_t arg) override {
+ Mutex::Autolock autoLock(mMsgLock);
+ mStatusEvent = event;
+ mEventArg = arg;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return ScopedAStatus::ok();
+ }
+
+ void testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+ vector<uint8_t>& eventData);
+
+ void testSessionEventEcho(shared_ptr<ICas>& mediaCas, const vector<uint8_t>& sessionId,
+ int32_t& event, int32_t& eventArg, vector<uint8_t>& eventData);
+
+ void testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
+ SessionIntent intent, ScramblingMode mode);
+
+ private:
+ int32_t mEvent = -1;
+ int32_t mEventArg = -1;
+ StatusEvent mStatusEvent;
+ bool mEventReceived = false;
+ vector<uint8_t> mEventData;
+ vector<uint8_t> mSessionId;
+ Mutex mMsgLock;
+ android::Condition mMsgCondition;
+};
+
+void MediaCasListener::testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+ vector<uint8_t>& eventData) {
+ mEventReceived = false;
+ auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
+ EXPECT_TRUE(returnStatus.isOk());
+
+ Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ ADD_FAILURE() << "event not received within timeout";
+ return;
+ }
+ }
+
+ EXPECT_EQ(mEvent, event);
+ EXPECT_EQ(mEventArg, eventArg);
+ EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testSessionEventEcho(shared_ptr<ICas>& mediaCas,
+ const vector<uint8_t>& sessionId, int32_t& event,
+ int32_t& eventArg, vector<uint8_t>& eventData) {
+ mEventReceived = false;
+ EXPECT_TRUE(mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData).isOk());
+
+ Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ ADD_FAILURE() << "event not received within timeout";
+ return;
+ }
+ }
+
+ EXPECT_TRUE(mSessionId == sessionId);
+ EXPECT_EQ(mEvent, event);
+ EXPECT_EQ(mEventArg, eventArg);
+ EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
+ SessionIntent intent, ScramblingMode mode) {
+ mEventReceived = false;
+ EXPECT_TRUE(mediaCas->openSession(intent, mode, sessionId).isOk());
+
+ Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ ADD_FAILURE() << "event not received within timeout";
+ return;
+ }
+ }
+ EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
+ EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
+}
+
+class MediaCasAidlTest : public testing::TestWithParam<string> {
+ public:
+ virtual void SetUp() override {
+ if (AServiceManager_isDeclared(GetParam().c_str())) {
+ SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+ mService = IMediaCasService::fromBinder(binder);
+ } else {
+ mService = nullptr;
+ }
+ ASSERT_NE(mService, nullptr);
+ }
+
+ shared_ptr<IMediaCasService> mService = nullptr;
+
+ protected:
+ static void description(const string& description) {
+ RecordProperty("description", description);
+ }
+
+ shared_ptr<ICas> mMediaCas;
+ shared_ptr<IDescrambler> mDescrambler;
+ shared_ptr<MediaCasListener> mCasListener;
+ typedef struct _OobInputTestParams {
+ const SubSample* subSamples;
+ int32_t numSubSamples;
+ int64_t imemSizeActual;
+ int64_t imemOffset;
+ int64_t imemSize;
+ int64_t srcOffset;
+ int64_t dstOffset;
+ } OobInputTestParams;
+
+ AssertionResult createCasPlugin(int32_t caSystemId);
+ AssertionResult openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
+ ScramblingMode mode);
+ AssertionResult descrambleTestInputBuffer(const shared_ptr<IDescrambler>& descrambler,
+ ScopedAStatus& descrambleStatus, uint8_t*& inMemory);
+ AssertionResult descrambleTestOobInput(const shared_ptr<IDescrambler>& descrambler,
+ ScopedAStatus& descrambleStatus,
+ const OobInputTestParams& params);
+};
+
+AssertionResult MediaCasAidlTest::createCasPlugin(int32_t caSystemId) {
+ bool isSystemIdSupported;
+ auto status = mService->isSystemIdSupported(caSystemId, &isSystemIdSupported);
+ bool skipDescrambler = false;
+ if (!status.isOk() || !isSystemIdSupported) {
+ return AssertionFailure();
+ }
+ bool isDescramblerSupported;
+ status = mService->isDescramblerSupported(caSystemId, &isDescramblerSupported);
+ if (!status.isOk() || !isDescramblerSupported) {
+ ALOGI("Skip Descrambler test since it's not required in cas.");
+ mDescrambler = nullptr;
+ skipDescrambler = true;
+ }
+
+ mCasListener = SharedRefBase::make<MediaCasListener>();
+ status = mService->createPlugin(caSystemId, mCasListener, &mMediaCas);
+ if (!status.isOk()) {
+ return AssertionFailure();
+ }
+ if (mMediaCas == nullptr) {
+ return AssertionFailure();
+ }
+
+ if (skipDescrambler) {
+ return AssertionSuccess();
+ }
+
+ status = mService->createDescrambler(caSystemId, &mDescrambler);
+ if (!status.isOk()) {
+ return AssertionFailure();
+ }
+
+ return AssertionResult(mDescrambler != nullptr);
+}
+
+AssertionResult MediaCasAidlTest::openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
+ ScramblingMode mode) {
+ return AssertionResult(mMediaCas->openSession(intent, mode, sessionId).isOk());
+}
+
+AssertionResult MediaCasAidlTest::descrambleTestInputBuffer(
+ const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
+ uint8_t*& sharedMemory) {
+ vector<SubSample> subSample(kSubSamples,
+ kSubSamples + (sizeof(kSubSamples) / sizeof(SubSample)));
+
+ int size = sizeof(kInBinaryBuffer);
+ auto fd = ashmem_create_region("vts-cas", size);
+ if (fd < 0) {
+ ALOGE("ashmem_create_region failed");
+ return AssertionFailure();
+ }
+
+ sharedMemory =
+ static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+ if (sharedMemory == reinterpret_cast<uint8_t*>(MAP_FAILED)) {
+ ALOGE("mmap failed");
+ return AssertionFailure();
+ }
+
+ memcpy(sharedMemory, kInBinaryBuffer, size);
+
+ auto dupFd = dup(fd);
+
+ SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
+ .heapBase.size = size,
+ .offset = 0,
+ .size = size};
+
+ SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
+ .heapBase.size = size,
+ .offset = 0,
+ .size = size};
+
+ DestinationBuffer dstBuffer;
+ dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
+
+ int32_t outBytes;
+ descrambleStatus = descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample,
+ srcBuffer, 0, dstBuffer, 0, &outBytes);
+ if (!descrambleStatus.isOk()) {
+ ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
+ outBytes, descrambleStatus.getDescription().c_str());
+ }
+ return AssertionResult(descrambleStatus.isOk());
+}
+
+AssertionResult MediaCasAidlTest::descrambleTestOobInput(
+ const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
+ const OobInputTestParams& params) {
+ vector<SubSample> subSample(params.subSamples, params.subSamples + params.numSubSamples);
+
+ auto fd = ashmem_create_region("vts-cas", params.imemSizeActual);
+ if (fd < 0) {
+ ALOGE("ashmem_create_region failed");
+ return AssertionFailure();
+ }
+
+ auto dupFd = dup(fd);
+
+ SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
+ .heapBase.size = params.imemSizeActual,
+ .offset = params.imemOffset,
+ .size = params.imemSize};
+
+ SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
+ .heapBase.size = params.imemSizeActual,
+ .offset = params.imemOffset,
+ .size = params.imemSize};
+
+ DestinationBuffer dstBuffer;
+ dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
+
+ int32_t outBytes;
+ descrambleStatus =
+ descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample, srcBuffer,
+ params.srcOffset, dstBuffer, params.dstOffset, &outBytes);
+ if (!descrambleStatus.isOk()) {
+ ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
+ outBytes, descrambleStatus.getDescription().c_str());
+ }
+ return AssertionResult(descrambleStatus.isOk());
+}
+
+TEST_P(MediaCasAidlTest, EnumeratePlugins) {
+ description("Test enumerate plugins");
+
+ vector<AidlCasPluginDescriptor> descriptors;
+ EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
+
+ if (descriptors.size() == 0) {
+ ALOGW("[ WARN ] enumeratePlugins list empty");
+ return;
+ }
+
+ for (size_t i = 0; i < descriptors.size(); i++) {
+ int32_t caSystemId = descriptors[i].caSystemId;
+
+ ASSERT_TRUE(createCasPlugin(caSystemId));
+ }
+}
+
+TEST_P(MediaCasAidlTest, TestInvalidSystemIdFails) {
+ description("Test failure for invalid system ID");
+
+ bool isSystemIdSupported;
+ auto status = mService->isSystemIdSupported(INVALID_SYSTEM_ID, &isSystemIdSupported);
+
+ EXPECT_TRUE(status.isOk());
+ ASSERT_FALSE(isSystemIdSupported);
+
+ bool isDescramblerSupported;
+ status = mService->isDescramblerSupported(INVALID_SYSTEM_ID, &isDescramblerSupported);
+
+ EXPECT_TRUE(status.isOk());
+ ASSERT_FALSE(isDescramblerSupported);
+
+ shared_ptr<ICas> mediaCas;
+ shared_ptr<MediaCasListener> casListener = SharedRefBase::make<MediaCasListener>();
+ status = mService->createPlugin(INVALID_SYSTEM_ID, casListener, &mediaCas);
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(mediaCas, nullptr);
+
+ shared_ptr<IDescrambler> descrambler;
+ status = mService->createDescrambler(INVALID_SYSTEM_ID, &descrambler);
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(descrambler, nullptr);
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyPluginInstalled) {
+ description("Test if ClearKey plugin is installed");
+
+ vector<AidlCasPluginDescriptor> descriptors;
+ EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
+
+ if (descriptors.size() == 0) {
+ ALOGW("[ WARN ] enumeratePlugins list empty");
+ }
+
+ for (size_t i = 0; i < descriptors.size(); i++) {
+ int32_t caSystemId = descriptors[i].caSystemId;
+ if (CLEAR_KEY_SYSTEM_ID == caSystemId) {
+ return;
+ }
+ }
+
+ ADD_FAILURE() << "ClearKey plugin not installed";
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeySessionClosedAfterRelease) {
+ description("Test that all sessions are closed after a MediaCas object is released");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+ vector<uint8_t> streamSessionId;
+ ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
+
+ EXPECT_TRUE(mMediaCas->release().isOk());
+
+ if (mDescrambler != nullptr) {
+ auto status = mDescrambler->setMediaCasSession(sessionId);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+
+ status = mDescrambler->setMediaCasSession(streamSessionId);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+ }
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyErrors) {
+ description("Test that invalid call sequences fail with expected error codes");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ /*
+ * Test MediaCas error codes
+ */
+ // Provision should fail with an invalid asset string
+ auto returnStatus = mMediaCas->provision("invalid asset string");
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_NO_LICENSE, returnStatus.getServiceSpecificError());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ // Open a session, then close it so that it should become invalid
+ vector<uint8_t> invalidSessionId;
+ ASSERT_TRUE(openCasSession(&invalidSessionId, intent, mode));
+ EXPECT_TRUE(mMediaCas->closeSession(invalidSessionId).isOk());
+
+ // processEcm should fail with an invalid session id
+ vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+ returnStatus = mMediaCas->processEcm(invalidSessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+ // processEcm should fail without provisioning
+ returnStatus = mMediaCas->processEcm(sessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_NOT_PROVISIONED, returnStatus.getServiceSpecificError());
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ // processEcm should fail with ecm with bad descriptor count
+ ecm[17] = 0x03; // change the descriptor count field to 3 (invalid)
+ returnStatus = mMediaCas->processEcm(sessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_UNKNOWN, returnStatus.getServiceSpecificError());
+
+ // processEcm should fail with ecm buffer that's too short
+ ecm.resize(8);
+ returnStatus = mMediaCas->processEcm(sessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::BAD_VALUE, returnStatus.getServiceSpecificError());
+
+ if (mDescrambler != nullptr) {
+ /*
+ * Test MediaDescrambler error codes
+ */
+ // setMediaCasSession should fail with an invalid session id
+ returnStatus = mDescrambler->setMediaCasSession(invalidSessionId);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
+
+ // descramble should fail without a valid session
+ ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+ uint8_t* sharedBuffer = nullptr;
+
+ ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+ EXPECT_EQ(Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED,
+ descrambleStatus.getServiceSpecificError());
+
+ // Now set a valid session, should still fail because no valid ecm is processed
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+ ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+ EXPECT_EQ(Status::ERROR_CAS_DECRYPT, descrambleStatus.getServiceSpecificError());
+
+ // Verify that requiresSecureDecoderComponent handles empty mime
+ bool requiresSecureDecoderComponent = true;
+ EXPECT_TRUE(
+ mDescrambler->requiresSecureDecoderComponent("", &requiresSecureDecoderComponent)
+ .isOk());
+ EXPECT_FALSE(requiresSecureDecoderComponent);
+
+ // Verify that requiresSecureDecoderComponent handles invalid mime
+ requiresSecureDecoderComponent = true;
+ EXPECT_TRUE(
+ mDescrambler->requiresSecureDecoderComponent("bad", &requiresSecureDecoderComponent)
+ .isOk());
+ EXPECT_FALSE(requiresSecureDecoderComponent);
+ }
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyApisWithSession) {
+ description("Test that valid call sequences with SessionEvent send and receive");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ vector<uint8_t> pvtData;
+ pvtData.resize(256);
+ EXPECT_TRUE(mMediaCas->setPrivateData(pvtData).isOk());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+ EXPECT_TRUE(mMediaCas->setSessionPrivateData(sessionId, pvtData).isOk());
+
+ vector<uint8_t> streamSessionId;
+ ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
+ EXPECT_TRUE(mMediaCas->setSessionPrivateData(streamSessionId, pvtData).isOk());
+
+ if (mDescrambler != nullptr) {
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(streamSessionId).isOk());
+ }
+
+ vector<uint8_t> nullPtrVector(0);
+ EXPECT_TRUE(mMediaCas->refreshEntitlements(3, nullPtrVector).isOk());
+
+ vector<uint8_t> refreshData{0, 1, 2, 3};
+ EXPECT_TRUE(mMediaCas->refreshEntitlements(10, refreshData).isOk());
+
+ int32_t eventID = 1;
+ int32_t eventArg = 2;
+ mCasListener->testEventEcho(mMediaCas, eventID, eventArg, nullPtrVector);
+ mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, nullPtrVector);
+
+ eventID = 3;
+ eventArg = 4;
+ vector<uint8_t> eventData{'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
+ mCasListener->testEventEcho(mMediaCas, eventID, eventArg, eventData);
+ mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, eventData);
+
+ mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
+
+ vector<uint8_t> clearKeyEmmData{'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
+ EXPECT_TRUE(mMediaCas->processEmm(clearKeyEmmData).isOk());
+
+ vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+ EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
+ EXPECT_TRUE(mMediaCas->processEcm(streamSessionId, ecm).isOk());
+
+ if (mDescrambler != nullptr) {
+ bool requiresSecureDecoderComponent = true;
+ EXPECT_TRUE(mDescrambler
+ ->requiresSecureDecoderComponent("video/avc",
+ &requiresSecureDecoderComponent)
+ .isOk());
+ EXPECT_FALSE(requiresSecureDecoderComponent);
+
+ ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+ uint8_t* sharedBuffer = nullptr;
+
+ ASSERT_TRUE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+
+ int compareResult =
+ memcmp(static_cast<const void*>(sharedBuffer),
+ static_cast<const void*>(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer));
+ EXPECT_EQ(0, compareResult);
+
+ EXPECT_TRUE(mDescrambler->release().isOk());
+ }
+
+ EXPECT_TRUE(mMediaCas->release().isOk());
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyOobFails) {
+ description("Test that oob descramble request fails with expected error");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+ if (mDescrambler != nullptr) {
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+ }
+
+ vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+ EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
+
+ if (mDescrambler != nullptr) {
+ ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+
+ // test invalid src buffer offset
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0xcccccc,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid src buffer size
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = 0xcccccc,
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid src buffer size
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 1,
+ .imemSize = -1,
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid srcOffset
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0xcccccc,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid dstOffset
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0xcccccc}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test detection of oob subsample sizes
+ const SubSample invalidSubSamples1[] = {{162, 0}, {0, 184}, {0, 0xdddddd}};
+
+ ASSERT_FALSE(descrambleTestOobInput(
+ mDescrambler, descrambleStatus,
+ {.subSamples = invalidSubSamples1,
+ .numSubSamples = sizeof(invalidSubSamples1) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test detection of overflowing subsample sizes
+ const SubSample invalidSubSamples2[] = {{162, 0}, {0, 184}, {2, -1}};
+
+ ASSERT_FALSE(descrambleTestOobInput(
+ mDescrambler, descrambleStatus,
+ {.subSamples = invalidSubSamples2,
+ .numSubSamples = sizeof(invalidSubSamples2) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ EXPECT_TRUE(mDescrambler->release().isOk());
+ }
+ EXPECT_TRUE(mMediaCas->release().isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasAidlTest);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IMediaCasService::descriptor)),
+ android::PrintInstanceNameToString);
+
+// Start thread pool to receive callbacks from AIDL service.
+int main(int argc, char** argv) {
+ InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 524242f..4dc3f6c 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -28,7 +28,6 @@
"compatibility_matrix.3.xml",
],
kernel_configs: [
- "kernel_config_p_4.4",
"kernel_config_p_4.9",
"kernel_config_p_4.14",
],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 53b9c7c..7ddf87a 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -207,6 +207,13 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.cas</name>
+ <interface>
+ <name>IMediaCasService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.confirmationui</name>
<version>1</version>
<interface>
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 4c23cbc..35e4650 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -107,10 +107,9 @@
ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
if (mConnectedHostEndpoints.count(in_hostEndpointId) > 0) {
mConnectedHostEndpoints.erase(in_hostEndpointId);
- return ndk::ScopedAStatus::ok();
- } else {
- return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
+
+ return ndk::ScopedAStatus::ok();
}
} // namespace contexthub
diff --git a/dumpstate/aidl/Android.bp b/dumpstate/aidl/Android.bp
index 63670bb..1eb8b32 100644
--- a/dumpstate/aidl/Android.bp
+++ b/dumpstate/aidl/Android.bp
@@ -31,7 +31,8 @@
enabled: false,
},
java: {
- enabled: false,
+ enabled: true,
+ sdk_version: "module_current",
},
},
versions_with_info: [
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/B237048744.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/B237048744.aidl
new file mode 100644
index 0000000..7fee851
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/B237048744.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+enum B237048744 {
+ V5 = 0,
+}
diff --git a/identity/aidl/android/hardware/identity/B237048744.aidl b/identity/aidl/android/hardware/identity/B237048744.aidl
new file mode 100644
index 0000000..24b16c0
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/B237048744.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.identity;
+
+@VintfStability
+enum B237048744 {
+ V5 /* bump only includes import changes */,
+}
diff --git a/identity/aidl/default/android.hardware.identity_credential.xml b/identity/aidl/default/android.hardware.identity_credential.xml
index 20b2710..a49ddca 100644
--- a/identity/aidl/default/android.hardware.identity_credential.xml
+++ b/identity/aidl/default/android.hardware.identity_credential.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<permissions>
- <feature name="android.hardware.identity_credential" version="202201" />
+ <feature name="android.hardware.identity_credential" version="202301" />
</permissions>
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index dd29819..54bf887 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -59,3 +59,16 @@
],
require_root: true,
}
+
+java_test_host {
+ name: "IdentityCredentialImplementedTest",
+ libs: [
+ "tradefed",
+ "vts-core-tradefed-harness",
+ ],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "vts",
+ ],
+ test_config: "IdentityCredentialImplementedTest.xml",
+}
diff --git a/identity/aidl/vts/IdentityCredentialImplementedTest.xml b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
new file mode 100644
index 0000000..4276ae6
--- /dev/null
+++ b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration description="Runs IdentityCredentialImplementedTest">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="jar" value="IdentityCredentialImplementedTest.jar" />
+ </test>
+</configuration>
diff --git a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
new file mode 100644
index 0000000..4936f8c
--- /dev/null
+++ b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.security.identity;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.RequiresDevice;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+// This is a host-test which executes shell commands on the device. It would be
+// nicer to have this be a Device test (like CTS) but this is currently not
+// possible, see https://source.android.com/docs/core/tests/vts
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class IdentityCredentialImplementedTest extends BaseHostJUnit4Test {
+ // Returns the ro.vendor.api_level or 0 if not set.
+ //
+ // Throws NumberFormatException if ill-formatted.
+ //
+ // Throws DeviceNotAvailableException if device is not available.
+ //
+ private int getVendorApiLevel() throws NumberFormatException, DeviceNotAvailableException {
+ String vendorApiLevelString =
+ getDevice().executeShellCommand("getprop ro.vendor.api_level").trim();
+ if (vendorApiLevelString.isEmpty()) {
+ return 0;
+ }
+ return Integer.parseInt(vendorApiLevelString);
+ }
+
+ // As of Android 14 VSR (vendor API level 34), Identity Credential is required at feature
+ // version 202301 or later.
+ @RequiresDevice
+ @Test
+ public void testIdentityCredentialIsImplemented() throws Exception {
+ int vendorApiLevel = getVendorApiLevel();
+ assumeTrue(vendorApiLevel >= 34);
+
+ final String minimumFeatureVersionNeeded = "202301";
+
+ String result = getDevice().executeShellCommand(
+ "pm has-feature android.hardware.identity_credential "
+ + minimumFeatureVersionNeeded);
+ if (!result.trim().equals("true")) {
+ fail("Identity Credential feature version " + minimumFeatureVersionNeeded
+ + " required but not found");
+ }
+ }
+}
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 4f5d821..2194529 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -4946,15 +4946,15 @@
TEST_P(ImportWrappedKeyTest, WrongDigest) {
auto wrapping_key_desc = AuthorizationSetBuilder()
.RsaEncryptionKey(2048, 65537)
- .Digest(Digest::SHA_2_512)
.Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)
.Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY)
.SetDefaultValidity();
ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
AuthorizationSetBuilder()
- .Digest(Digest::SHA_2_256)
+ .Digest(Digest::SHA_2_512)
.Padding(PaddingMode::RSA_OAEP)));
}
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index ddc6ee0..01602ab 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -59,7 +59,10 @@
const std::shared_ptr<IVibratorCallback>& callback) {
LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
if (callback != nullptr) {
- std::thread([=] {
+ // Note that thread lambdas aren't using implicit capture [=], to avoid capturing "this",
+ // which may be asynchronously destructed.
+ // If "this" is needed, use [sharedThis = this->ref<Vibrator>()].
+ std::thread([timeoutMs, callback] {
LOG(VERBOSE) << "Starting on on another thread";
usleep(timeoutMs * 1000);
LOG(VERBOSE) << "Notifying on complete";
@@ -87,7 +90,7 @@
constexpr size_t kEffectMillis = 100;
if (callback != nullptr) {
- std::thread([=] {
+ std::thread([callback] {
LOG(VERBOSE) << "Starting perform on another thread";
usleep(kEffectMillis * 1000);
LOG(VERBOSE) << "Notifying perform complete";
@@ -174,7 +177,8 @@
}
}
- std::thread([=] {
+ // The thread may theoretically outlive the vibrator, so take a proper reference to it.
+ std::thread([sharedThis = this->ref<Vibrator>(), composite, callback] {
LOG(VERBOSE) << "Starting compose on another thread";
for (auto& e : composite) {
@@ -185,7 +189,7 @@
<< e.scale;
int32_t durationMs;
- getPrimitiveDuration(e.primitive, &durationMs);
+ sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
usleep(durationMs * 1000);
}
@@ -396,7 +400,7 @@
}
}
- std::thread([=] {
+ std::thread([totalDuration, callback] {
LOG(VERBOSE) << "Starting composePwle on another thread";
usleep(totalDuration * 1000);
if (callback != nullptr) {
diff --git a/vibrator/aidl/default/VibratorManager.cpp b/vibrator/aidl/default/VibratorManager.cpp
index 7cf9e6a..26edf5a 100644
--- a/vibrator/aidl/default/VibratorManager.cpp
+++ b/vibrator/aidl/default/VibratorManager.cpp
@@ -66,7 +66,7 @@
ndk::ScopedAStatus VibratorManager::triggerSynced(
const std::shared_ptr<IVibratorCallback>& callback) {
LOG(INFO) << "Vibrator Manager trigger synced";
- std::thread([=] {
+ std::thread([callback] {
if (callback != nullptr) {
LOG(INFO) << "Notifying perform complete";
callback->onComplete();
diff --git a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
index 44fa3be..e8ed26a 100644
--- a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp
@@ -96,6 +96,7 @@
if (!(capabilities & IVibratorManager::CAP_SYNC)) return;
if (vibratorIds.empty()) return;
EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
+ EXPECT_TRUE(manager->cancelSynced().isOk());
}
TEST_P(VibratorAidl, PrepareSyncedEmptySetIsInvalid) {
@@ -208,6 +209,7 @@
EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk());
Status status = manager->triggerSynced(callback);
EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
+ EXPECT_TRUE(manager->cancelSynced().isOk());
}
}