STHAL 2.4

This version of the soundtrigger HAL adds support for dynamic resource
management by the HAL, allowing it to refuse to start/load and to
preemptively stop/unload models at its discretion.

This give the HAL more freedom to make resource allocation decisions
and avoids the need to precisely model the various constraints and
have them enforced by the framework.

Bug: 178722883
Change-Id: I58807407417fc099b7538e685309d2c846ed66fd
This commit is contained in:
Ytai Ben-Tsvi 2021-01-25 16:56:25 -08:00
parent f3eeb55ed5
commit a2cd51a0b9
7 changed files with 394 additions and 1 deletions

View file

@ -529,7 +529,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.soundtrigger</name>
<version>2.3</version>
<version>2.3-4</version>
<interface>
<name>ISoundTriggerHw</name>
<instance>default</instance>

View file

@ -0,0 +1,21 @@
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
name: "android.hardware.soundtrigger@2.4",
root: "android.hardware",
srcs: [
"ISoundTriggerHw.hal",
"ISoundTriggerHwCallback.hal",
"ISoundTriggerHwGlobalCallback.hal",
],
interfaces: [
"android.hardware.audio.common@2.0",
"android.hardware.soundtrigger@2.0",
"android.hardware.soundtrigger@2.1",
"android.hardware.soundtrigger@2.2",
"android.hardware.soundtrigger@2.3",
"android.hidl.base@1.0",
"android.hidl.safe_union@1.0",
],
gen_java: true,
}

View file

@ -0,0 +1,190 @@
/*
* Copyright 2021 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.soundtrigger@2.4;
import @2.0::SoundModelHandle;
import @2.1::ISoundTriggerHw.SoundModel;
import @2.1::ISoundTriggerHw.PhraseSoundModel;
import @2.3::ISoundTriggerHw;
import @2.3::RecognitionConfig;
import ISoundTriggerHwCallback;
import ISoundTriggerHwGlobalCallback;
/**
* SoundTrigger HAL interface. Used for hardware recognition of hotwords
* and other sounds.
*
* Important notes about the threading model:
* ==========================================
* Both this interface and the corresponding callback interface use a synchronized calling
* convention. This model comes with some advantages, but also with some risks of deadlocks if the
* implementation does not handle this correctly. Please consider the following:
* - After stopRecognition() returns no more recognition events for that model may be sent. This
* implies that any queues holding such events must be flushed before the call returns and that
* may imply that callback from the HAL to the client are done while stopRecognition() is blocked.
* This is OK, and supported by the framework.
* - Similarly, the same relationship applies between unloadModel() and subsequent callbacks to
* modelUnloaded().
* - Other than these two cases, calls into the HAL *MAY NOT* block on callbacks from the HAL, or
* else deadlock conditions may result, which may be handled by rebooting of the HAL process and
* cause service outages.
*
* Similarly, it is expected that a single call to startRecognition() generates at most one event
* (the model automatically becomes stopped when the event occurs, until explicitly started again)
* and that after a modelUnloaded() event no more events would be sent regarding the model.
* Note that a getModelState() call may generate a recognition event, but this event DOES NOT modify
* the model state - the model remains started.
*
* The HAL is expected to correctly handle a stopRecognition() call even after it sent an event
* indicating that recognition is stopped and an unloadModel() call even after it sent an event
* indicating that it has been unloaded. This is required in order to prevent race conditions
* between these calls. This also implies that model handles should generally not be reused until
* explicitly unloaded. To avoid the rare possibility of running out of handles, the framework will
* call unloadModel() on models that have been preemptively unloaded by the HAL.
*
* Due to the asynchronous nature of recognition events and preemptive model unloading, the HAL must
* correctly handle requests that would have been valid before an event has been delivered, but
* became moot as result of the event. Namely:
* - stopRecognition() may be called on a model that has already delivered an event and became
* inactive as a result. The HAL must return a successful return code in this case.
* - Furthermore, if a model is preemptively unloaded after it triggers (typically, this would
* happen when it is first aborted and immediately preemptively unloaded), stopRecognition() may
* be called on it. The HAL must return a successful return code in this case.
* - startRecognition() may be called on a model that has been preemptively unloaded. In this case,
* the HAL must return -EBUSY to indicate that the operation is temporarily unsuccessful.
* - unloadSoundModel() may be called on a model that has been preemptively unloaded. The HAL must
* return a successful return code in this case.
*
* Important notes about resource constraints and concurrency
* =========================================================
* Up until this version, the framework would enforce concurrency constraints expressed by the
* Properties presented by the soundtrigger instance. These include constraints on the maximum
* amount of models that can be loaded at the same time and on running recognition while capturing
* from the microphone.
* This version changes the approach for how these constraints are modeled, both offering the HAL
* implementation more flexibility and simplifying the framework's job in enforcing these
* limitations. Note that there is no change for how the framework behaves with earlier versions,
* everything described below only applies to this version and onward.
* The way this is achieved is as following:
* - The framework will no longer enforce constraints on concurrent loading of models, as expressed
* in the Properties.maxSoundModels field (this property is merely a hint at this point and may be
* deprecated in the future.
* - The framework will no longer enforce constraints on concurrency of audio recording and
* soundtrigger operation, as expressed in the Properties.concurrentCapture field (this property
* is merely a hint at this point and may be deprecated in the future).
* - The framework will no longer enforce constraints on concurrent loading of models, as expressed
* in the Properties (these properties are merely hints at this point and may be deprecated in the
* future.
* - The HAL implementation is free to reject starting of any model at any time by having the
* respective start*() method return -EBUSY.
* - The HAL implementation is free to reject loading of any model at any time by having the
* respective load*() method return -EBUSY.
* - The HAL implementation is free to preemptively stop a previously started model at its own
* discretion (for example, if a higher priority use-case which cannot coexist with detection
* has been requested). The HAL must notify the framework of the preemption by sending a
* recognition event with an `ABORT` status. The implementation must NOT attempt to restart the
* recognition automatically when conditions change.
* - The HAL implementation is free to preemptively unload a previously loaded model at its own
* discretion (for example, if a higher-priority model is being loaded and the two cannot
* coexist). When doing so, it must first abort the detection if active (as per above) and then
* notify the framework of the unload using the newly added modelUnloaded callback.
* - When conditions change, such that a model that couldn't previously load or start or that had
* previously been preemptively stopped or unloaded, the HAL must notify the framework via the
* newly added tryAgain() callback. This callback is not a guarantee that any operation would now
* succeed, but merely a hint that retrying something that had previously failed, now MAY succeed.
* Until this callback arrives, the framework may assume that any operation that had previously
* failed or aborted would still fail if retried, so the implementation should not forget to
* deliver it. There are no guarantees regarding how the framework may respond to this event and
* the order in which it may choose to reload/restart its models. Typically, as result of this
* event the framework will make a single attempt per model to bring this model to its desired
* state (loaded, started).
*/
interface ISoundTriggerHw extends @2.3::ISoundTriggerHw {
/**
* This will get called at most once per every attachment to the service.
*
* All events not tied to a specific model should go through this callback.
*/
registerGlobalCallback(ISoundTriggerHwGlobalCallback callback);
/**
* Load a sound model. Once loaded, recognition of this model can be
* started and stopped.
* The implementation returns a unique handle used by other functions
* (unloadSoundModel(), startRecognition*(), etc...
*
* Must have the exact same semantics as loadSoundModel from ISoundTriggerHw@2.3 except that the
* return values have changed and that there is no cookie provided (the implementation may pass
* any value to the callback, as it is ignored).
*
* @param soundModel A SoundModel structure describing the sound model
* to load.
* @param callback The callback interface on which the soundModelCallback*()
* method must be called upon completion and modelUnloaded() upon preempted unload.
* @return retval Operation completion status: 0 in case of success,
* -EBUSY in case the operation is temporarily unavailable (but possible in general).
* @return modelHandle A unique handle assigned by the HAL for use by the
* framework when controlling activity for this sound model.
*/
loadSoundModel_2_4(SoundModel soundModel, ISoundTriggerHwCallback callback)
generates (int32_t retval, SoundModelHandle modelHandle);
/**
* Load a key phrase sound model. Once loaded, recognition of this model can
* be started and stopped. Only one active recognition per model at a time.
* The SoundTrigger service must handle concurrent recognition requests by
* different users/applications on the same model.
* The implementation returns a unique handle used by other functions
* (unloadSoundModel(), startRecognition*(), etc...
*
* Must have the exact same semantics as loadPhraseSoundModel from ISoundTriggerHw@2.3 except
* that the return values have changed and that there is no cookie provided (the implementation
* may pass any value to the callback, as it is ignored).
*
* @param soundModel A PhraseSoundModel structure describing the sound model
* to load.
* @param callback The callback interface on which the soundModelCallback*()
* method must be called upon completion and modelUnloaded() upon preempted unload.
* @return retval Operation completion status: 0 in case of success,
* -EBUSY in case the operation is temporarily unavailable (but possible in general).
* @return modelHandle A unique handle assigned by the HAL for use by the
* framework when controlling activity for this sound model.
*/
loadPhraseSoundModel_2_4(PhraseSoundModel soundModel, ISoundTriggerHwCallback callback)
generates (int32_t retval, SoundModelHandle modelHandle);
/**
* Start recognition on a given model. Only one recognition active
* at a time per model. Once recognition succeeds or fails, the callback
* associated with the model handle is called.
*
* Must have the exact same semantics as startRecognition from ISoundTriggerHw@2.3 except that
* there are different expectations of the return value and that there is no cookie provided
* (the implementation may pass any value to the callback, as it is ignored).
*
* @param modelHandle the handle of the sound model to use for recognition
* @param config A RecognitionConfig structure containing attributes of the
* recognition to perform
* @param callback The callback interface on which the recognitionCallback()
* method must be called upon recognition.
* @return retval Operation completion status: 0 in case of success,
* -EBUSY in case the operation is temporarily unavailable (but possible in general), or in
* case model has been preemtively unloaded.
*/
startRecognition_2_4(SoundModelHandle modelHandle, RecognitionConfig config)
generates (int32_t retval);
};

View file

@ -0,0 +1,34 @@
/*
* Copyright 2021 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.soundtrigger@2.4;
import @2.0::SoundModelHandle;
import @2.1::ISoundTriggerHwCallback;
/**
* SoundTrigger HAL per-model Callback interface.
*/
interface ISoundTriggerHwCallback extends @2.1::ISoundTriggerHwCallback {
/**
* Callback method called by the HAL when a model has been unloaded at the HAL implementation's
* discretion. Only a stopped model may be unloaded.
* This event is NOT sent as part of an unload sequence initiated by the client.
*
* @param model The model handle.
*/
modelUnloaded(SoundModelHandle model);
};

View file

@ -0,0 +1,32 @@
/*
* Copyright 2021 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.soundtrigger@2.4;
/**
* SoundTrigger HAL callback interface for events not associated with a particular model.
*/
interface ISoundTriggerHwGlobalCallback {
/**
* Callback method called by the HAL whenever internal conditions have been made available, such
* that a call that would previously have failed with an -EBUSY status may now succeed.
* There is no guarantee that any call would succeed following this event. It is merely a hint
* to the client that it may retry.
* Conversely, any call that have failed previously with -EBUSY is guaranteed to fail again if
* retried, until this callback is delivered.
*/
onResourcesAvailable();
};

View file

@ -0,0 +1,32 @@
//
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
cc_test {
name: "VtsHalSoundtriggerV2_4TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalSoundtriggerV2_4TargetTest.cpp"],
static_libs: [
"android.hardware.soundtrigger@2.0",
"android.hardware.soundtrigger@2.1",
"android.hardware.soundtrigger@2.2",
"android.hardware.soundtrigger@2.3",
"android.hardware.soundtrigger@2.4",
],
test_suites: [
"general-tests",
"vts",
],
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (C) 2021 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 "SoundTriggerHidlHalTest"
#include <android-base/logging.h>
#include <android/hardware/audio/common/2.0/types.h>
#include <android/hardware/soundtrigger/2.4/ISoundTriggerHwGlobalCallback.h>
#include <android/hardware/soundtrigger/2.4/ISoundTriggerHw.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
using ::android::sp;
using ::android::hardware::Return;
using ::android::hardware::Status;
using ::android::hardware::soundtrigger::V2_4::ISoundTriggerHw;
using ::android::hardware::soundtrigger::V2_4::ISoundTriggerHwGlobalCallback;
/**
* Test class holding the instance of the SoundTriggerHW service to test.
* The passed parameter is the registered name of the implementing service
* supplied by INSTANTIATE_TEST_SUITE_P() call.
*/
class SoundTriggerHidlTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override {
mSoundtrigger = ISoundTriggerHw::getService(GetParam());
ASSERT_NE(mSoundtrigger, nullptr);
LOG(INFO) << "Test is remote " << mSoundtrigger->isRemote();
}
protected:
sp<ISoundTriggerHw> mSoundtrigger;
};
/**
* Empty test is in place to ensure service is initialized.
* Due to the nature of SoundTrigger HAL providing an interface for
* proprietary or vendor specific implementations, limited testing on
* individual APIs is possible.
*/
TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {}
class GlobalCallback : public ISoundTriggerHwGlobalCallback {
Return<void> onResourcesAvailable() override {
return Status::ok();
}
};
/**
* Test ISoundTriggerHw::registerGlobalCallback method
*
* Verifies that:
* - the implementation implements the method
* - the method returns no error
*/
TEST_P(SoundTriggerHidlTest, RegisterGlobalCallback) {
Return<void> hidlReturn;
sp<ISoundTriggerHwGlobalCallback> callback = new GlobalCallback();
hidlReturn = mSoundtrigger->registerGlobalCallback(callback);
EXPECT_TRUE(hidlReturn.isOk());
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundTriggerHidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, SoundTriggerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
android::hardware::PrintInstanceNameToString);