Merge changes I392933f8,I5e4da0c3,I2134b15e into main
* changes:
audio: Add optional 'DriverInterface::getPosition' method.
audio: Create ModulePrimary and ModuleStub
audio: Move tinyALSA-specific code to Module/StreamAlsa
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 3e06595..81c99f7 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -4,6 +4,9 @@
"name": "VtsHalAudioCoreTargetTest"
},
{
+ "name": "audio_policy_config_xml_converter_tests"
+ },
+ {
"name": "VtsHalAudioEffectFactoryTargetTest"
},
{
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 934c7ee..19b2397 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -149,6 +149,50 @@
],
}
+cc_test {
+ name: "audio_policy_config_xml_converter_tests",
+ vendor_available: true,
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_static",
+ "latest_android_hardware_audio_core_ndk_static",
+ ],
+ shared_libs: [
+ "libaudio_aidl_conversion_common_ndk",
+ "libaudioaidlcommon",
+ "libaudioutils",
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libmedia_helper",
+ "libstagefright_foundation",
+ "libutils",
+ "libxml2",
+ ],
+ header_libs: [
+ "libaudio_system_headers",
+ "libaudioaidl_headers",
+ "libxsdc-utils",
+ ],
+ generated_sources: [
+ "audio_policy_configuration_aidl_default",
+ ],
+ generated_headers: [
+ "audio_policy_configuration_aidl_default",
+ ],
+ srcs: [
+ "AudioPolicyConfigXmlConverter.cpp",
+ "tests/AudioPolicyConfigXmlConverterTest.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ "-DBACKEND_NDK",
+ ],
+ test_suites: ["general-tests"],
+}
+
cc_defaults {
name: "aidlaudioeffectservice_defaults",
defaults: [
diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
index 2848d71..7452c8e 100644
--- a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
+++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
@@ -137,7 +137,7 @@
SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS),
SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD),
SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD_MA),
- SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD),
+ SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1),
SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2),
SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD),
SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3_JOC),
diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
index 94501a8..090d585 100644
--- a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
+++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
@@ -38,9 +38,10 @@
const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
const SurroundSoundConfig& getSurroundSoundConfig();
- private:
+ // Public for testing purposes.
static const SurroundSoundConfig& getDefaultSurroundSoundConfig();
+ private:
const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>&
getXsdcConfig() const {
return mConverter.getXsdcConfig();
diff --git a/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp b/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp
new file mode 100644
index 0000000..572bc5a
--- /dev/null
+++ b/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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 <memory>
+// #include <string>
+// #include <vector>
+
+#include <android-base/macros.h>
+#include <gtest/gtest.h>
+#define LOG_TAG "AudioPolicyConfigXmlConverterTest"
+#include <log/log.h>
+
+#include <core-impl/AudioPolicyConfigXmlConverter.h>
+#include <media/AidlConversionCppNdk.h>
+
+using aidl::android::hardware::audio::core::internal::AudioPolicyConfigXmlConverter;
+using aidl::android::media::audio::common::AudioFormatDescription;
+
+namespace {
+
+void ValidateAudioFormatDescription(const AudioFormatDescription& format) {
+ auto conv = ::aidl::android::aidl2legacy_AudioFormatDescription_audio_format_t(format);
+ ASSERT_TRUE(conv.ok()) << format.toString();
+}
+
+} // namespace
+
+TEST(AudioPolicyConfigXmlConverterTest, DefaultSurroundSoundConfigIsValid) {
+ auto config = AudioPolicyConfigXmlConverter::getDefaultSurroundSoundConfig();
+ for (const auto& family : config.formatFamilies) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat));
+ SCOPED_TRACE(family.primaryFormat.toString());
+ for (const auto& sub : family.subFormats) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(sub));
+ }
+ }
+}
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 1a7c3d4..0354e3c 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -51,7 +51,7 @@
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
- Parameter::Specific specific = getDefaultParamSpecific();
+ auto specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
@@ -65,8 +65,13 @@
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
- Parameter::Specific getDefaultParamSpecific() {
- AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
+ std::optional<Parameter::Specific> getDefaultParamSpecific() {
+ auto aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
+ if (!isParameterValid<AcousticEchoCanceler, Range::acousticEchoCanceler>(aec,
+ mDescriptor)) {
+ return std::nullopt;
+ }
+
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
return specific;
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index bbb11fc..624d5d2 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -48,7 +48,7 @@
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
- Parameter::Specific specific = getDefaultParamSpecific();
+ std::optional<Parameter::Specific> specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
@@ -62,9 +62,13 @@
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
- Parameter::Specific getDefaultParamSpecific() {
+ std::optional<Parameter::Specific> getDefaultParamSpecific() {
NoiseSuppression ns =
NoiseSuppression::make<NoiseSuppression::level>(NoiseSuppression::Level::MEDIUM);
+ if (!isParameterValid<NoiseSuppression, Range::noiseSuppression>(ns, mDescriptor)) {
+ return std::nullopt;
+ }
+
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::noiseSuppression>(ns);
return specific;
@@ -85,7 +89,9 @@
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
- const binder_exception_t expected = EX_NONE;
+ const bool valid =
+ isParameterValid<NoiseSuppression, Range::noiseSuppression>(ns, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// set parameter
Parameter expectParam;
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index 141efc1..62046f3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
@@ -18,6 +18,7 @@
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
+#include <condition_variable>
#include <chrono>
#include <memory>
@@ -28,6 +29,8 @@
namespace automotive {
namespace vehicle {
+using ::android::base::ScopedLockAssertion;
+
class RecurrentTimerTest : public testing::Test {
public:
std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
@@ -35,6 +38,15 @@
std::scoped_lock<std::mutex> lockGuard(mLock);
mCallbacks.push_back(token);
+ mCond.notify_all();
+ });
+ }
+
+ bool waitForCalledCallbacks(size_t count, size_t timeoutInMs) {
+ std::unique_lock<std::mutex> uniqueLock(mLock);
+ return mCond.wait_for(uniqueLock, std::chrono::milliseconds(timeoutInMs), [this, count] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mCallbacks.size() >= count;
});
}
@@ -54,6 +66,7 @@
}
private:
+ std::condition_variable mCond;
std::mutex mLock;
std::vector<size_t> mCallbacks GUARDED_BY(mLock);
};
@@ -66,12 +79,11 @@
auto action = getCallback(0);
timer.registerTimerCallback(interval, action);
- std::this_thread::sleep_for(std::chrono::seconds(1));
+ // Should only takes 1s, use 5s as timeout to be safe.
+ ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+ << "Not enough callbacks called before timeout";
timer.unregisterTimerCallback(action);
-
- // Theoretically trigger 10 times, but check for at least 9 times to be stable.
- ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
}
TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
@@ -92,10 +104,11 @@
timer.registerTimerCallback(interval, action);
- std::this_thread::sleep_for(std::chrono::seconds(1));
+ // Should only takes 1s, use 5s as timeout to be safe.
+ ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+ << "Not enough callbacks called before timeout";
- // Theoretically trigger 10 times, but check for at least 9 times to be stable.
- ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+ timer.unregisterTimerCallback(action);
}
TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
@@ -114,7 +127,9 @@
std::this_thread::sleep_for(std::chrono::milliseconds(200));
- ASSERT_TRUE(getCalledCallbacks().empty());
+ // Should be 0, but in rare cases there might be 1 events in the queue while the timer is
+ // being destroyed.
+ ASSERT_LE(getCalledCallbacks().size(), 1u);
}
TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
@@ -132,7 +147,11 @@
auto action3 = getCallback(3);
timer.registerTimerCallback(interval3, action3);
- std::this_thread::sleep_for(std::chrono::seconds(1));
+ // In 1s, we should generate 10 + 20 + 33 = 63 events.
+ // Here we are waiting for more events to make sure we receive enough events for each actions.
+ // Use 5s as timeout to be safe.
+ ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 70u, /* timeoutInMs= */ 5000))
+ << "Not enough callbacks called before timeout";
timer.unregisterTimerCallback(action1);
timer.unregisterTimerCallback(action2);
@@ -152,20 +171,18 @@
action3Count++;
}
}
- // Theoretically trigger 10 times, but check for at least 9 times to be stable.
- ASSERT_GE(action1Count, static_cast<size_t>(9));
- // Theoretically trigger 20 times, but check for at least 15 times to be stable.
- ASSERT_GE(action2Count, static_cast<size_t>(15));
- // Theoretically trigger 33 times, but check for at least 25 times to be stable.
- ASSERT_GE(action3Count, static_cast<size_t>(25));
+
+ ASSERT_GE(action1Count, static_cast<size_t>(10));
+ ASSERT_GE(action2Count, static_cast<size_t>(20));
+ ASSERT_GE(action3Count, static_cast<size_t>(33));
}
TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
RecurrentTimer timer;
- // 0.02s
- int64_t interval1 = 20000000;
- // 0.01s
- int64_t interval2 = 10000000;
+ // 0.2s
+ int64_t interval1 = 200'000'000;
+ // 0.1s
+ int64_t interval2 = 100'000'000;
auto action = getCallback(0);
for (int i = 0; i < 10; i++) {
@@ -175,10 +192,9 @@
clearCalledCallbacks();
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
- // Theoretically trigger 10 times, but check for at least 9 times to be stable.
- ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+ // Should only takes 1s, use 5s as timeout to be safe.
+ ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+ << "Not enough callbacks called before timeout";
timer.unregisterTimerCallback(action);
diff --git a/bluetooth/audio/OWNERS b/bluetooth/audio/OWNERS
index a8e9bda..f3657ca 100644
--- a/bluetooth/audio/OWNERS
+++ b/bluetooth/audio/OWNERS
@@ -1,4 +1,6 @@
+# Bug component: 27441
+
include platform/packages/modules/Bluetooth:/OWNERS
-cheneyni@google.com
aliceypkuo@google.com
+quocbaodo@google.com
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index e03fb58..3e6953f 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -15,16 +15,20 @@
],
tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
- shared_libs: [
+ static_libs: [
"android.hardware.audio.common-V1-ndk",
"android.hardware.bluetooth.audio-V3-ndk",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
+ "android.media.audio.common.types-V2-ndk",
+ ],
+ shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
"libfmq",
],
+ test_config: "VtsHalBluetoothAudioTargetTest.xml",
test_suites: [
"general-tests",
"vts",
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.xml b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.xml
new file mode 100644
index 0000000..7b02685
--- /dev/null
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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 VtsHalBluetoothAudioTargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+ <!-- Skips test module if ro.product.first_api_level < 33. -->
+ <option name="min-api-level" value="33" />
+ </object>
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalBluetoothAudioTargetTest->/data/local/tmp/VtsHalBluetoothAudioTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalBluetoothAudioTargetTest" />
+ </test>
+</configuration>
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
index c72cbde..4f342b2 100644
--- a/compatibility_matrices/build/vintf_compatibility_matrix.go
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -35,10 +35,10 @@
pctx = android.NewPackageContext("android/vintf")
assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{
- Command: `${assembleVintfCmd} -i ${inputs} -o ${out}`,
+ Command: `${assembleVintfCmd} -i ${inputs} -o ${out} ${extraParams}`,
CommandDeps: []string{"${assembleVintfCmd}"},
Description: "assemble_vintf -i ${inputs}",
- }, "inputs")
+ }, "inputs", "extraParams")
xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{
Command: `$XmlLintCmd --quiet --schema $xsd $in > /dev/null && touch -a $out`,
@@ -64,6 +64,13 @@
// list of kernel_config modules to be combined to final output
Kernel_configs []string
+
+ // Default is "default" for compatibility matrices on /vendor
+ // and /odm, and "disallow" for compatibility matrices on /system,
+ // /product, and /system_ext.
+ // If value is "only", only android.* HALs are allowed. If value
+ // is "disallow", none of android.* HALs are allowed.
+ Core_hals *string
}
type vintfCompatibilityMatrixRule struct {
@@ -166,7 +173,8 @@
Implicits: inputPaths,
Output: g.genFile,
Args: map[string]string{
- "inputs": strings.Join(inputPaths.Strings(), ":"),
+ "inputs": strings.Join(inputPaths.Strings(), ":"),
+ "extraParams": strings.Join(g.getExtraParams(), " "),
},
})
g.generateValidateBuildAction(ctx, g.genFile, schema.Path())
@@ -191,3 +199,23 @@
},
}
}
+
+// Return extra parameters to assemble_vintf.
+func (g *vintfCompatibilityMatrixRule) getExtraParams() []string {
+ var extraParams []string
+
+ coreHalsStrategy := proptools.StringDefault(
+ g.properties.Core_hals,
+ g.defaultCoreHalsStrategy(),
+ )
+ extraParams = append(extraParams, "--core-hals", proptools.ShellEscape(coreHalsStrategy))
+ return extraParams
+}
+
+func (g *vintfCompatibilityMatrixRule) defaultCoreHalsStrategy() string {
+ // TODO(b/290408770): default to "disallow" for FCMs
+
+ // For Device (vendor, odm) compatibility matrix, default is
+ // to not check anything.
+ return "default"
+}
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
new file mode 100755
index 0000000..88b7a42
--- /dev/null
+++ b/compatibility_matrices/bump.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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.
+#
+"""
+Creates the next compatibility matrix.
+
+Requires libvintf Level.h to be updated before executing this script.
+"""
+
+import argparse
+import os
+import pathlib
+import shutil
+import subprocess
+import textwrap
+
+
+def check_call(*args, **kwargs):
+ print(args)
+ subprocess.check_call(*args, **kwargs)
+
+
+def check_output(*args, **kwargs):
+ print(args)
+ return subprocess.check_output(*args, **kwargs)
+
+
+class Bump(object):
+
+ def __init__(self, cmdline_args):
+ self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
+ self.interfaces_dir = self.top / "hardware/interfaces"
+
+ self.current_level = cmdline_args.current
+ self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
+ self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
+
+ self.next_level = cmdline_args.next
+ self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
+ self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
+
+ self.level_to_letter = self.get_level_to_letter_mapping()
+ print("Found level mapping in libvintf Level.h:", self.level_to_letter)
+
+ def run(self):
+ self.bump_kernel_configs()
+ self.copy_matrix()
+ self.edit_android_bp()
+ self.edit_android_mk()
+
+ def get_level_to_letter_mapping(self):
+ levels_file = self.top / "system/libvintf/include/vintf/Level.h"
+ with open(levels_file) as f:
+ lines = f.readlines()
+ pairs = [
+ line.split("=", maxsplit=2) for line in lines if "=" in line
+ ]
+ return {
+ level.strip().removesuffix(","): letter.strip()
+ for letter, level in pairs
+ }
+
+ def bump_kernel_configs(self):
+ check_call([
+ self.top / "kernel/configs/tools/bump.py",
+ self.level_to_letter[self.current_level].lower(),
+ self.level_to_letter[self.next_level].lower(),
+ ])
+
+ def copy_matrix(self):
+ shutil.copyfile(self.current_xml, self.next_xml)
+
+ def edit_android_bp(self):
+ android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
+
+ with open(android_bp, "r+") as f:
+ if self.next_module_name not in f.read():
+ f.seek(0, 2) # end of file
+ f.write("\n")
+ f.write(
+ textwrap.dedent(f"""\
+ vintf_compatibility_matrix {{
+ name: "{self.next_module_name}",
+ }}
+ """))
+
+ next_kernel_configs = check_output(
+ """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
+ cwd=self.top / "kernel/configs" /
+ self.level_to_letter[self.next_level].lower(),
+ text=True,
+ shell=True,
+ ).splitlines()
+ print(next_kernel_configs)
+
+ check_call([
+ "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
+ "-str", self.next_xml.name, android_bp
+ ])
+
+ check_call([
+ "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
+ "-a",
+ self.next_xml.relative_to(android_bp.parent), android_bp
+ ])
+
+ check_call([
+ "bpmodify", "-w", "-m", self.next_module_name, "-property",
+ "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
+ ])
+
+ def edit_android_mk(self):
+ android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
+ with open(android_mk) as f:
+ if self.next_module_name in f.read():
+ return
+ f.seek(0)
+ lines = f.readlines()
+ current_module_line_number = None
+ for line_number, line in enumerate(lines):
+ if self.current_module_name in line:
+ current_module_line_number = line_number
+ break
+ assert current_module_line_number is not None
+ lines.insert(current_module_line_number + 1,
+ f" {self.next_module_name} \\\n")
+ with open(android_mk, "w") as f:
+ f.write("".join(lines))
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("current",
+ type=str,
+ help="VINTF level of the current version (e.g. 9)")
+ parser.add_argument("next",
+ type=str,
+ help="VINTF level of the next version (e.g. 10)")
+ cmdline_args = parser.parse_args()
+
+ Bump(cmdline_args).run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 93beb92..1c2cd50 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -134,7 +134,7 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.biometrics.face</name>
<version>2</version>
<interface>
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 50aa2b7..7194ebe 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -23,7 +23,14 @@
@VintfStability
parcelable BufferDescriptorInfo {
/**
- * The name of the buffer in ASCII. Useful for debugging/tracing.
+ * The name of the buffer in null-terminated ASCII. Useful for debugging/tracing.
+ *
+ * NOTE: While a well behaved client will ensure it passes a null-terminated string
+ * within the 128-byte limit, the IAllocator service implementation should be
+ * be defensive against malformed input. As such, it is recommended that
+ * IAllocator implementations proactively do `name[127] = 0` upon receiving
+ * an allocation request to enusre that the string is definitely
+ * null-terminated regardless of what the client sent.
*/
byte[128] name;
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index f401643..1d8cc13 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -272,7 +272,11 @@
{
std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
- callbacks_.emplace_back(LinkedCallback::Make(ref<Health>(), callback));
+ auto linked_callback_result = LinkedCallback::Make(ref<Health>(), callback);
+ if (!linked_callback_result.ok()) {
+ return ndk::ScopedAStatus::fromStatus(-linked_callback_result.error().code());
+ }
+ callbacks_.emplace_back(std::move(*linked_callback_result));
// unlock
}
diff --git a/health/aidl/default/LinkedCallback.cpp b/health/aidl/default/LinkedCallback.cpp
index 2985ffe..26e99f9 100644
--- a/health/aidl/default/LinkedCallback.cpp
+++ b/health/aidl/default/LinkedCallback.cpp
@@ -24,7 +24,7 @@
namespace aidl::android::hardware::health {
-std::unique_ptr<LinkedCallback> LinkedCallback::Make(
+::android::base::Result<std::unique_ptr<LinkedCallback>> LinkedCallback::Make(
std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback) {
std::unique_ptr<LinkedCallback> ret(new LinkedCallback());
binder_status_t linkRet =
@@ -32,7 +32,7 @@
reinterpret_cast<void*>(ret.get()));
if (linkRet != ::STATUS_OK) {
LOG(WARNING) << __func__ << "Cannot link to death: " << linkRet;
- return nullptr;
+ return ::android::base::Error(-linkRet);
}
ret->service_ = service;
ret->callback_ = std::move(callback);
diff --git a/health/aidl/default/LinkedCallback.h b/health/aidl/default/LinkedCallback.h
index 82490a7..da494c9 100644
--- a/health/aidl/default/LinkedCallback.h
+++ b/health/aidl/default/LinkedCallback.h
@@ -20,6 +20,7 @@
#include <aidl/android/hardware/health/IHealthInfoCallback.h>
#include <android-base/macros.h>
+#include <android-base/result.h>
#include <android/binder_auto_utils.h>
#include <health-impl/Health.h>
@@ -34,8 +35,8 @@
// service->death_reciepient() should be from CreateDeathRecipient().
// Not using a strong reference to |service| to avoid circular reference. The lifetime
// of |service| must be longer than this LinkedCallback object.
- static std::unique_ptr<LinkedCallback> Make(std::shared_ptr<Health> service,
- std::shared_ptr<IHealthInfoCallback> callback);
+ static ::android::base::Result<std::unique_ptr<LinkedCallback>> Make(
+ std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback);
// Automatically unlinkToDeath upon destruction. So, it is always safe to reinterpret_cast
// the cookie back to the LinkedCallback object.
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
index e4d4cbe..607ceb3 100644
--- a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
@@ -36,10 +36,9 @@
interface IThreadChip {
void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
void close();
- void reset();
+ void hardwareReset();
void sendSpinelFrame(in byte[] frame);
const int ERROR_FAILED = 1;
- const int ERROR_INVALID_ARGS = 2;
- const int ERROR_NO_BUFS = 3;
- const int ERROR_BUSY = 4;
+ const int ERROR_NO_BUFS = 2;
+ const int ERROR_BUSY = 3;
}
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
index eebaa46..e695623 100644
--- a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -30,19 +30,14 @@
const int ERROR_FAILED = 1;
/**
- * The invalid arguments.
- */
- const int ERROR_INVALID_ARGS = 2;
-
- /**
* Insufficient buffers available to send frames.
*/
- const int ERROR_NO_BUFS = 3;
+ const int ERROR_NO_BUFS = 2;
/**
* Service is busy and could not service the operation.
*/
- const int ERROR_BUSY = 4;
+ const int ERROR_BUSY = 3;
/**
* This method initializes the Thread HAL instance. If open completes
@@ -51,9 +46,10 @@
*
* @param callback A IThreadChipCallback callback instance.
*
+ * @throws EX_ILLEGAL_ARGUMENT if the callback handle is invalid (for example, it is null).
+ *
* @throws ServiceSpecificException with one of the following values:
* - ERROR_FAILED The interface cannot be opened due to an internal error.
- * - ERROR_INVALID_ARGS The callback handle is invalid (for example, it is null).
* - ERROR_BUSY This interface is in use.
*/
void open(in IThreadChipCallback callback);
@@ -64,11 +60,14 @@
void close();
/**
- * This method resets the Thread HAL internal state. The callback registered by
- * `open()` won’t be reset and the resource allocated by `open()` won’t be free.
+ * This method hardware resets the Thread radio chip via the physical reset pin.
+ * The callback registered by `open()` won’t be reset and the resource allocated
+ * by `open()` won’t be free.
+ *
+ * @throws EX_UNSUPPORTED_OPERATION if the Thread radio chip doesn't support the hardware reset.
*
*/
- void reset();
+ void hardwareReset();
/**
* This method sends a spinel frame to the Thread HAL.
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 8b938d2..bcd5704 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -79,7 +79,6 @@
"fuzzer.cpp",
],
- required: ["ot-rcp"],
fuzz_config: {
cc: [
"zhanglongxia@google.com",
diff --git a/threadnetwork/aidl/default/fuzzer.cpp b/threadnetwork/aidl/default/fuzzer.cpp
index 512708d..fb6e548 100644
--- a/threadnetwork/aidl/default/fuzzer.cpp
+++ b/threadnetwork/aidl/default/fuzzer.cpp
@@ -22,7 +22,7 @@
using android::fuzzService;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- char url[] = "spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=2";
+ char url[] = "spinel+hdlc+null:///dev/null";
auto service = ndk::SharedRefBase::make<ThreadChip>(url);
fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
index 94d1e93..3d38cb8 100644
--- a/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -17,6 +17,8 @@
#include "thread_chip.hpp"
#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <utils/Log.h>
@@ -46,20 +48,36 @@
mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(handleReceivedFrameJump, this,
mRxFrameBuffer);
} else {
- ALOGE("The protocol \"%s\" is not supported!", protocol);
- exit(1);
+ ALOGE("The protocol \"%s\" is not supported", protocol);
+ exit(EXIT_FAILURE);
}
CHECK_NE(mSpinelInterface, nullptr);
+
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
}
-void ThreadChip::clientDeathCallback(void* context) {
- reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
+ThreadChip::~ThreadChip() {
+ AIBinder_DeathRecipient_delete(mDeathRecipient.get());
}
-void ThreadChip::clientDeathCallback(void) {
- ALOGW("Thread Network HAL client is dead.");
- close();
+void ThreadChip::onBinderDiedJump(void* context) {
+ reinterpret_cast<ThreadChip*>(context)->onBinderDied();
+}
+
+void ThreadChip::onBinderDied(void) {
+ ALOGW("Thread Network HAL client is dead");
+}
+
+void ThreadChip::onBinderUnlinkedJump(void* context) {
+ reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
+}
+
+void ThreadChip::onBinderUnlinked(void) {
+ ALOGW("ThreadChip binder is unlinked");
+ deinitChip();
}
void ThreadChip::handleReceivedFrameJump(void* context) {
@@ -76,75 +94,83 @@
}
ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
- ndk::ScopedAStatus status;
- AIBinder* binder;
+ ndk::ScopedAStatus status = initChip(in_callback);
- VerifyOrExit(mCallback == nullptr,
- status = errorStatus(ERROR_BUSY, "Interface is already opened"));
- VerifyOrExit(in_callback != nullptr,
- status = errorStatus(ERROR_INVALID_ARGS, "The callback is NULL"));
- binder = in_callback->asBinder().get();
- VerifyOrExit(binder != nullptr,
- status = errorStatus(ERROR_FAILED, "Failed to get the callback binder"));
- mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
- VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
- status = errorStatus(ERROR_FAILED, "Failed to link the binder to death"));
- VerifyOrExit(mSpinelInterface->Init(mUrl) == OT_ERROR_NONE,
- status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
-
- mCallback = in_callback;
- ot::Posix::Mainloop::Manager::Get().Add(*this);
- status = ndk::ScopedAStatus::ok();
-
-exit:
- if (!status.isOk()) {
- if (mBinderDeathRecipient != nullptr) {
- AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
- mBinderDeathRecipient = nullptr;
- }
- ALOGW("Open failed, error: %s", status.getDescription().c_str());
+ if (status.isOk()) {
+ AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
+ ALOGI("Open IThreadChip successfully");
} else {
- ALOGI("open()");
+ ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
}
return status;
}
+ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+ if (in_callback == nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ } else if (mCallback == nullptr) {
+ if (mSpinelInterface->Init(mUrl) != OT_ERROR_NONE) {
+ return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
+ }
+
+ mCallback = in_callback;
+ ot::Posix::Mainloop::Manager::Get().Add(*this);
+ return ndk::ScopedAStatus::ok();
+ } else {
+ return errorStatus(ERROR_BUSY, "Interface has been opened");
+ }
+}
+
ndk::ScopedAStatus ThreadChip::close() {
- VerifyOrExit(mCallback != nullptr);
- mCallback = nullptr;
- mSpinelInterface->Deinit();
+ ndk::ScopedAStatus status;
+ std::shared_ptr<IThreadChipCallback> callback = mCallback;
- ot::Posix::Mainloop::Manager::Get().Remove(*this);
+ status = deinitChip();
+ if (status.isOk()) {
+ if (callback != nullptr) {
+ AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
+ }
- AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
- mBinderDeathRecipient = nullptr;
+ ALOGI("Close IThreadChip successfully");
+ } else {
+ ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
+ }
-exit:
- ALOGI("close()");
- return ndk::ScopedAStatus::ok();
+ return status;
+}
+
+ndk::ScopedAStatus ThreadChip::deinitChip() {
+ if (mCallback != nullptr) {
+ mSpinelInterface->Deinit();
+ ot::Posix::Mainloop::Manager::Get().Remove(*this);
+ mCallback = nullptr;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
ndk::ScopedAStatus status;
otError error;
- VerifyOrExit(mCallback != nullptr,
- status = errorStatus(ERROR_FAILED, "The interface is not open"));
-
- error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
- in_frame.size());
- if (error == OT_ERROR_NONE) {
- status = ndk::ScopedAStatus::ok();
- } else if (error == OT_ERROR_NO_BUFS) {
- status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
- } else if (error == OT_ERROR_BUSY) {
- status = errorStatus(ERROR_BUSY, "The interface is busy");
+ if (mCallback == nullptr) {
+ status = errorStatus(ERROR_FAILED, "The interface is not open");
} else {
- status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+ error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+ in_frame.size());
+ if (error == OT_ERROR_NONE) {
+ status = ndk::ScopedAStatus::ok();
+ } else if (error == OT_ERROR_NO_BUFS) {
+ status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
+ } else if (error == OT_ERROR_BUSY) {
+ status = errorStatus(ERROR_BUSY, "The interface is busy");
+ } else {
+ status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+ }
}
-exit:
if (!status.isOk()) {
ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
}
@@ -152,8 +178,11 @@
return status;
}
-ndk::ScopedAStatus ThreadChip::reset() {
- mSpinelInterface->HardwareReset();
+ndk::ScopedAStatus ThreadChip::hardwareReset() {
+ if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
ALOGI("reset()");
return ndk::ScopedAStatus::ok();
}
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
index 294190a..1ab6d54 100644
--- a/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -22,6 +22,7 @@
#include "lib/spinel/spinel_interface.hpp"
#include "mainloop.hpp"
+#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
#include <utils/Mutex.h>
@@ -33,26 +34,31 @@
class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
public:
ThreadChip(char* url);
+ ~ThreadChip();
ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
ndk::ScopedAStatus close() override;
ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
- ndk::ScopedAStatus reset() override;
+ ndk::ScopedAStatus hardwareReset() override;
void Update(otSysMainloopContext& context) override;
void Process(const otSysMainloopContext& context) override;
private:
- static void clientDeathCallback(void* context);
- void clientDeathCallback(void);
+ static void onBinderDiedJump(void* context);
+ void onBinderDied(void);
+ static void onBinderUnlinkedJump(void* context);
+ void onBinderUnlinked(void);
static void handleReceivedFrameJump(void* context);
void handleReceivedFrame(void);
ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
+ ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
+ ndk::ScopedAStatus deinitChip();
ot::Url::Url mUrl;
std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
std::shared_ptr<IThreadChipCallback> mCallback;
- AIBinder_DeathRecipient* mBinderDeathRecipient;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
};
} // namespace threadnetwork
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
index 04c6dea..5925b54 100644
--- a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -91,7 +91,7 @@
ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
EXPECT_TRUE(thread_chip->open(callback).isOk());
- EXPECT_TRUE(thread_chip->reset().isOk());
+ EXPECT_TRUE(thread_chip->hardwareReset().isOk());
}
TEST_P(ThreadNetworkAidl, SendSpinelFrame) {