Merge "Merge tm-qpr-dev-plus-aosp-without-vendor@9467136" into stage-aosp-master

This commit is contained in:
Xin Li
2023-01-13 07:32:46 +00:00
committed by Android (Google) Code Review
6 changed files with 133 additions and 58 deletions

View File

@@ -190,6 +190,40 @@ const std::vector<ConfigDeclaration> kVehicleProperties = {
},
.initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}},
{.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SELECT),
.access = VehiclePropertyAccess::WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
.minInt32Value = 0,
.maxInt32Value = 3},
VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
.minInt32Value = 0,
.maxInt32Value = 3},
VehicleAreaConfig{.areaId = SEAT_2_LEFT,
.minInt32Value = 0,
.maxInt32Value = 3},
VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
.minInt32Value = 0,
.maxInt32Value = 3}}},
.initialValue = {.int32Values = {1}}},
{.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SET),
.access = VehiclePropertyAccess::WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
.minInt32Value = 0,
.maxInt32Value = 3},
VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
.minInt32Value = 0,
.maxInt32Value = 3},
VehicleAreaConfig{.areaId = SEAT_2_LEFT,
.minInt32Value = 0,
.maxInt32Value = 3},
VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
.minInt32Value = 0,
.maxInt32Value = 3}}},
.initialValue = {.int32Values = {1}}},
{.config = {.prop = toInt(VehicleProperty::SEAT_BELT_BUCKLED),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,

View File

@@ -83,8 +83,9 @@ class RecurrentTimer final {
// each time we might introduce outdated elements to the top. We must make sure the heap is
// always valid from the top.
void removeInvalidCallbackLocked() REQUIRES(mLock);
// Pops the next closest callback (must be valid) from the heap.
std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock);
// Gets the next calblack to run (must be valid) from the heap, update its nextTime and put
// it back to the heap.
std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock);
};
} // namespace vehicle

View File

@@ -101,68 +101,71 @@ void RecurrentTimer::removeInvalidCallbackLocked() {
}
}
std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() {
std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) {
std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]);
mCallbackQueue.pop_back();
auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1];
auto nextCallback = callbackInfo->callback;
// intervalCount is the number of interval we have to advance until we pass now.
size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1;
callbackInfo->nextTime += intervalCount * callbackInfo->interval;
std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
// Make sure the first element is always valid.
removeInvalidCallbackLocked();
return info;
return nextCallback;
}
void RecurrentTimer::loop() {
std::unique_lock<std::mutex> uniqueLock(mLock);
std::vector<std::shared_ptr<Callback>> callbacksToRun;
while (true) {
// Wait until the timer exits or we have at least one recurrent callback.
mCond.wait(uniqueLock, [this] {
ScopedLockAssertion lockAssertion(mLock);
return mStopRequested || mCallbackQueue.size() != 0;
});
int64_t interval;
{
std::unique_lock<std::mutex> uniqueLock(mLock);
ScopedLockAssertion lockAssertion(mLock);
// Wait until the timer exits or we have at least one recurrent callback.
mCond.wait(uniqueLock, [this] {
ScopedLockAssertion lockAssertion(mLock);
return mStopRequested || mCallbackQueue.size() != 0;
});
int64_t interval;
if (mStopRequested) {
return;
}
// The first element is the nearest next event.
int64_t nextTime = mCallbackQueue[0]->nextTime;
int64_t now = uptimeNanos();
if (nextTime > now) {
interval = nextTime - now;
} else {
interval = 0;
}
}
// Wait for the next event or the timer exits.
if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
ScopedLockAssertion lockAssertion(mLock);
return mStopRequested;
})) {
return;
}
// Wait for the next event or the timer exits.
if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
ScopedLockAssertion lockAssertion(mLock);
return mStopRequested;
})) {
return;
}
{
ScopedLockAssertion lockAssertion(mLock);
int64_t now = uptimeNanos();
now = uptimeNanos();
callbacksToRun.clear();
while (mCallbackQueue.size() > 0) {
int64_t nextTime = mCallbackQueue[0]->nextTime;
if (nextTime > now) {
break;
}
std::unique_ptr<CallbackInfo> info = popNextCallbackLocked();
info->nextTime += info->interval;
auto callback = info->callback;
mCallbackQueue.push_back(std::move(info));
std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
(*callback)();
callbacksToRun.push_back(getNextCallbackLocked(now));
}
}
// Do not execute the callback while holding the lock.
for (size_t i = 0; i < callbacksToRun.size(); i++) {
(*callbacksToRun[i])();
}
}
}

View File

@@ -186,6 +186,33 @@ TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
}
TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) {
// We want to avoid the following situation:
// Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try
// to obtain an internal lock inside timer.
// Meanwhile an recurrent action happens with timer holding an internal lock. The action
// tries to obtain the lock currently hold by the caller.
// The solution is that while calling recurrent actions, timer must not hold the internal lock.
std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
std::mutex lock;
for (size_t i = 0; i < 1000; i++) {
std::scoped_lock<std::mutex> lockGuard(lock);
auto action = std::make_shared<RecurrentTimer::Callback>([&lock] {
// While calling this function, the timer must not hold lock in order not to dead
// lock.
std::scoped_lock<std::mutex> lockGuard(lock);
});
// 10ms
int64_t interval = 10'000'000;
timer->registerTimerCallback(interval, action);
// Sleep for a little while to let the recurrent actions begin.
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Make sure we stop the timer before we destroy lock.
timer.reset();
}
} // namespace vehicle
} // namespace automotive
} // namespace hardware

View File

@@ -68,7 +68,7 @@ ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback)
IGnssCallback::GnssSystemInfo systemInfo = {
.yearOfHw = 2022,
.name = "Google Mock GNSS Implementation AIDL v2",
.name = "Google, Cuttlefish, AIDL v2",
};
status = sGnssCallback->gnssSetSystemInfoCb(systemInfo);
if (!status.isOk()) {

View File

@@ -190,12 +190,13 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
size_t index = 0;
// validate packet information
if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage packet information
const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
const FmqRequestDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
@@ -212,13 +213,14 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
inputs.reserve(numberOfInputOperands);
for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
// validate input operand information
if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::inputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
data[index].inputOperandInformation();
data.at(index).inputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -229,12 +231,13 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::inputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
const uint32_t dimension = data[index].inputOperandDimensionValue();
const uint32_t dimension = data.at(index).inputOperandDimensionValue();
index++;
// store result
@@ -251,13 +254,14 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
outputs.reserve(numberOfOutputOperands);
for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
// validate output operand information
if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::outputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
data[index].outputOperandInformation();
data.at(index).outputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -268,12 +272,13 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::outputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
const uint32_t dimension = data[index].outputOperandDimensionValue();
const uint32_t dimension = data.at(index).outputOperandDimensionValue();
index++;
// store result
@@ -290,12 +295,13 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
slots.reserve(numberOfPools);
for (size_t pool = 0; pool < numberOfPools; ++pool) {
// validate input operand information
if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::poolIdentifier) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const int32_t poolId = data[index].poolIdentifier();
const int32_t poolId = data.at(index).poolIdentifier();
index++;
// store result
@@ -303,17 +309,17 @@ nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
}
// validate measureTiming
if (data[index].getDiscriminator() != discriminator::measureTiming) {
if (index >= data.size() || data.at(index).getDiscriminator() != discriminator::measureTiming) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage measureTiming
const V1_2::MeasureTiming measure = data[index].measureTiming();
const V1_2::MeasureTiming measure = data.at(index).measureTiming();
index++;
// validate packet information
if (index != packetSize) {
return NN_ERROR() << "FMQ Result packet ill-formed";
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// return request
@@ -328,12 +334,13 @@ nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::T
size_t index = 0;
// validate packet information
if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage packet information
const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
const FmqResultDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
@@ -349,12 +356,13 @@ nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::T
outputShapes.reserve(numberOfOperands);
for (size_t operand = 0; operand < numberOfOperands; ++operand) {
// validate operand information
if (data[index].getDiscriminator() != discriminator::operandInformation) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::operandInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage operand information
const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
const FmqResultDatum::OperandInformation& operandInfo = data.at(index).operandInformation();
index++;
const bool isSufficient = operandInfo.isSufficient;
const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
@@ -364,12 +372,13 @@ nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::T
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::operandDimensionValue) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage dimension
const uint32_t dimension = data[index].operandDimensionValue();
const uint32_t dimension = data.at(index).operandDimensionValue();
index++;
// store result
@@ -381,12 +390,13 @@ nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::T
}
// validate execution timing
if (data[index].getDiscriminator() != discriminator::executionTiming) {
if (index >= data.size() ||
data.at(index).getDiscriminator() != discriminator::executionTiming) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage execution timing
const V1_2::Timing timing = data[index].executionTiming();
const V1_2::Timing timing = data.at(index).executionTiming();
index++;
// validate packet information