Merge Android U (ab/10368041)

Bug: 291102124
Merged-In: I7b6fffac2ada0e039f79bad8cc9b4d954e9c3460
Change-Id: I9466127d8d0fa38df36ca99f704853b2db871e67
This commit is contained in:
Xin Li 2023-08-25 13:29:30 -07:00
commit 879960bdce
3210 changed files with 151775 additions and 21100 deletions

View file

@ -2,10 +2,29 @@
Directory structure of the audio HAL related code.
Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
based on an existing one.
## Directory Structure for AIDL audio HAL
## Directory Structure
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.
* `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

View file

@ -292,7 +292,6 @@ aidl_interface {
sdk_version: "module_current",
},
},
frozen: true,
versions_with_info: [
{
version: "1",
@ -304,6 +303,7 @@ aidl_interface {
],
},
],
frozen: true,
}

View file

@ -279,8 +279,10 @@ package android.audio.policy.configuration {
method @NonNull public String getRawName();
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HOTWORD_TAP;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_LOOKBACK;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;

View file

@ -191,6 +191,8 @@
<xs:enumeration value="AUDIO_INPUT_FLAG_HW_AV_SYNC" />
<xs:enumeration value="AUDIO_INPUT_FLAG_DIRECT" />
<xs:enumeration value="AUDIO_INPUT_FLAG_ULTRASOUND" />
<xs:enumeration value="AUDIO_INPUT_FLAG_HOTWORD_TAP" />
<xs:enumeration value="AUDIO_INPUT_FLAG_HW_LOOKBACK" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="audioInOutFlags">

View file

@ -44,9 +44,15 @@ aidl_interface {
},
},
versions_with_info: [
{
version: "1",
imports: ["android.hardware.audio.core.sounddose-V1"],
},
// IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
// add the latest frozen version to versions_with_info
],
frozen: true,
}
// Note: This should always be one version ahead of the last frozen version

View file

@ -0,0 +1 @@
7acf835db643d39414afbbbbcda816e2d7e8c77a

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.audio.sounddose;
@VintfStability
interface ISoundDoseFactory {
@nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose(in @utf8InCpp String module);
}

View file

@ -1,46 +0,0 @@
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_defaults {
name: "aidlsounddoseservice_defaults",
vendor: true,
header_libs: [
"libsounddoseaidl_headers",
],
}
cc_library {
name: "libsounddoseserviceexampleimpl",
defaults: [
"aidlsounddoseservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_core_sounddose_ndk_shared",
"latest_android_hardware_audio_sounddose_ndk_shared",
],
export_include_dirs: ["include"],
srcs: [
"SoundDoseFactory.cpp",
],
shared_libs: [
"libaudioservicesounddoseimpl",
"libbase",
"libbinder_ndk",
],
visibility: [
"//hardware/interfaces/audio/common/all-versions/default/service",
],
}
cc_library_headers {
name: "libsounddoseaidl_headers",
export_include_dirs: ["include"],
vendor_available: true,
host_supported: true,
}

View file

@ -1,49 +0,0 @@
/*
* 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 "AHAL_SoundDoseFactory"
#include "SoundDoseFactory.h"
#include <android-base/logging.h>
#include <core-impl/SoundDose.h>
namespace aidl::android::hardware::audio::sounddose {
using ::aidl::android::hardware::audio::core::sounddose::SoundDose;
ndk::ScopedAStatus SoundDoseFactory::getSoundDose(const std::string& in_module,
std::shared_ptr<ISoundDose>* _aidl_return) {
auto soundDoseIt = mSoundDoseBinderMap.find(in_module);
if (soundDoseIt != mSoundDoseBinderMap.end()) {
*_aidl_return = ISoundDose::fromBinder(soundDoseIt->second);
LOG(DEBUG) << __func__
<< ": returning cached instance of ISoundDose: " << _aidl_return->get()
<< " for module " << in_module;
return ndk::ScopedAStatus::ok();
}
auto soundDose = ndk::SharedRefBase::make<SoundDose>();
mSoundDoseBinderMap[in_module] = soundDose->asBinder();
*_aidl_return = soundDose;
LOG(DEBUG) << __func__ << ": returning new instance of ISoundDose: " << _aidl_return->get()
<< " for module " << in_module;
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::audio::sounddose

View file

@ -1,38 +0,0 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
#include <aidl/android/hardware/audio/sounddose/BnSoundDoseFactory.h>
#include <android/binder_interface_utils.h>
#include <unordered_map>
namespace aidl::android::hardware::audio::sounddose {
using ::aidl::android::hardware::audio::core::sounddose::ISoundDose;
class SoundDoseFactory : public BnSoundDoseFactory {
public:
ndk::ScopedAStatus getSoundDose(const std::string& module,
std::shared_ptr<ISoundDose>* _aidl_return) override;
private:
std::unordered_map<std::string, ndk::SpAIBinder> mSoundDoseBinderMap;
};
} // namespace aidl::android::hardware::audio::sounddose

View file

@ -71,6 +71,7 @@ class SoundDoseFactory : public testing::TestWithParam<std::string> {
std::shared_ptr<ISoundDoseFactory> soundDoseFactory;
};
// @VsrTest = VSR-5.5-002.001
TEST_P(SoundDoseFactory, GetSoundDoseForSameModule) {
const std::string module = "primary";

View file

@ -3593,6 +3593,7 @@ ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
return ndk::ScopedAStatus::ok();
}
// @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose, SameInstance) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
@ -3604,6 +3605,7 @@ TEST_P(AudioCoreSoundDose, SameInstance) {
<< "getSoundDose must return the same interface instance across invocations";
}
// @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose, GetSetOutputRs2UpperBound) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
@ -3618,6 +3620,7 @@ TEST_P(AudioCoreSoundDose, GetSetOutputRs2UpperBound) {
EXPECT_TRUE(isSupported) << "Getting/Setting RS2 upper bound must be supported";
}
// @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose, CheckDefaultRs2UpperBound) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
@ -3628,6 +3631,7 @@ TEST_P(AudioCoreSoundDose, CheckDefaultRs2UpperBound) {
EXPECT_EQ(rs2Value, ISoundDose::DEFAULT_MAX_RS2);
}
// @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
@ -3638,6 +3642,7 @@ TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
<< "Registering sound dose callback twice should throw EX_ILLEGAL_STATE";
}
// @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose, RegisterSoundDoseNullCallbackThrowsException) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";

View file

@ -38,13 +38,11 @@ cc_binary {
name: "android.hardware.audio.service",
init_rc: ["android.hardware.audio.service.rc"],
vintf_fragments: ["android.hardware.audio.sounddose-aidl.xml"],
relative_install_path: "hw",
vendor: true,
defaults: [
"android_hardware_audio_config_defaults",
"latest_android_hardware_audio_sounddose_ndk_shared",
],
srcs: ["service.cpp"],
@ -56,7 +54,6 @@ cc_binary {
],
shared_libs: [
"//hardware/interfaces/audio/aidl/sounddose/default:libsounddoseserviceexampleimpl",
"libcutils",
"libbinder",
"libbinder_ndk",

View file

@ -1,7 +0,0 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.audio.sounddose</name>
<version>1</version>
<fqname>ISoundDoseFactory/default</fqname>
</hal>
</manifest>

View file

@ -20,10 +20,6 @@
#include <string>
#include <vector>
#include <SoundDoseFactory.h>
#include <android-base/logging.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
@ -37,8 +33,6 @@ using android::OK;
using InterfacesList = std::vector<std::string>;
using aidl::android::hardware::audio::sounddose::SoundDoseFactory;
/** Try to register the provided factories in the provided order.
* If any registers successfully, do not register any other and return true.
* If all fail, return false.
@ -144,6 +138,10 @@ int main(int /* argc */, char* /* argv */ []) {
"android.hardware.bluetooth.audio-impl",
"createIBluetoothAudioProviderFactory",
},
{
"android.hardware.audio.sounddose-vendor-impl",
"createISoundDoseFactory",
},
};
// clang-format on
@ -171,13 +169,5 @@ int main(int /* argc */, char* /* argv */ []) {
}
}
// Register ISoundDoseFactory interface as a workaround for using the audio AIDL HAL
auto soundDoseDefault = ndk::SharedRefBase::make<SoundDoseFactory>();
const std::string soundDoseDefaultName =
std::string() + SoundDoseFactory::descriptor + "/default";
binder_status_t status = AServiceManager_addService(soundDoseDefault->asBinder().get(),
soundDoseDefaultName.c_str());
CHECK_EQ(STATUS_OK, status);
joinRpcThreadpool();
}

View file

@ -715,13 +715,11 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest {
}
void releasePatchIfNeeded() {
if (getDevice()) {
if (areAudioPatchesSupported() && mHasPatch) {
if (getDevice() && areAudioPatchesSupported() && mHasPatch) {
EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
mHasPatch = false;
}
}
}
void waitForCapturePositionAdvance(StreamReader& reader, uint64_t* firstPosition = nullptr,
uint64_t* lastPosition = nullptr) {

View file

@ -43,7 +43,15 @@ aidl_interface {
"android.media.audio.common.types-V2",
],
},
{
version: "3",
imports: [
"android.hardware.audio.common-V1",
"android.media.audio.common.types-V2",
],
},
],
frozen: true,
}

View file

@ -0,0 +1 @@
bc0ead0d35057635fdb88f5353686cbbc6c65dcd

View file

@ -0,0 +1,45 @@
/*
* Copyright (C) 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.automotive.audiocontrol;
@Backing(type="int") @VintfStability
enum AudioFocusChange {
NONE = 0,
GAIN = 1,
GAIN_TRANSIENT = 2,
GAIN_TRANSIENT_MAY_DUCK = 3,
GAIN_TRANSIENT_EXCLUSIVE = 4,
LOSS = ((-1) * GAIN) /* -1 */,
LOSS_TRANSIENT = ((-1) * GAIN_TRANSIENT) /* -2 */,
LOSS_TRANSIENT_CAN_DUCK = ((-1) * GAIN_TRANSIENT_MAY_DUCK) /* -3 */,
}

View file

@ -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.automotive.audiocontrol;
@VintfStability
parcelable AudioGainConfigInfo {
int zoneId;
String devicePortAddress;
int volumeIndex;
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 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.automotive.audiocontrol;
@VintfStability
parcelable DuckingInfo {
int zoneId;
String[] deviceAddressesToDuck;
String[] deviceAddressesToUnduck;
String[] usagesHoldingFocus;
@nullable android.hardware.audio.common.PlaybackTrackMetadata[] playbackMetaDataHoldingFocus;
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 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.automotive.audiocontrol;
@VintfStability
interface IAudioControl {
/**
* @deprecated use {@link android.hardware.audio.common.PlaybackTrackMetadata} instead.
*/
oneway void onAudioFocusChange(in String usage, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusChange);
oneway void onDevicesToDuckChange(in android.hardware.automotive.audiocontrol.DuckingInfo[] duckingInfos);
oneway void onDevicesToMuteChange(in android.hardware.automotive.audiocontrol.MutingInfo[] mutingInfos);
oneway void registerFocusListener(in android.hardware.automotive.audiocontrol.IFocusListener listener);
oneway void setBalanceTowardRight(in float value);
oneway void setFadeTowardFront(in float value);
oneway void onAudioFocusChangeWithMetaData(in android.hardware.audio.common.PlaybackTrackMetadata playbackMetaData, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusChange);
oneway void setAudioDeviceGainsChanged(in android.hardware.automotive.audiocontrol.Reasons[] reasons, in android.hardware.automotive.audiocontrol.AudioGainConfigInfo[] gains);
oneway void registerGainCallback(in android.hardware.automotive.audiocontrol.IAudioGainCallback callback);
void setModuleChangeCallback(in android.hardware.automotive.audiocontrol.IModuleChangeCallback callback);
void clearModuleChangeCallback();
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.audiocontrol;
@VintfStability
interface IAudioGainCallback {
oneway void onAudioDeviceGainsChanged(in android.hardware.automotive.audiocontrol.Reasons[] reasons, in android.hardware.automotive.audiocontrol.AudioGainConfigInfo[] gains);
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 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.automotive.audiocontrol;
@VintfStability
interface IFocusListener {
oneway void abandonAudioFocus(in String usage, in int zoneId);
oneway void requestAudioFocus(in String usage, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusGain);
oneway void abandonAudioFocusWithMetaData(in android.hardware.audio.common.PlaybackTrackMetadata playbackMetaData, in int zoneId);
oneway void requestAudioFocusWithMetaData(in android.hardware.audio.common.PlaybackTrackMetadata playbackMetaData, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusGain);
}

View file

@ -0,0 +1,38 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.audiocontrol;
@VintfStability
interface IModuleChangeCallback {
oneway void onAudioPortsChanged(in android.media.audio.common.AudioPort[] audioPorts);
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 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.automotive.audiocontrol;
@VintfStability
parcelable MutingInfo {
int zoneId;
String[] deviceAddressesToMute;
String[] deviceAddressesToUnmute;
}

View file

@ -0,0 +1,47 @@
/*
* 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.automotive.audiocontrol;
@Backing(type="int") @VintfStability
enum Reasons {
FORCED_MASTER_MUTE = 0x1,
REMOTE_MUTE = 0x2,
TCU_MUTE = 0x4,
ADAS_DUCKING = 0x8,
NAV_DUCKING = 0x10,
PROJECTION_DUCKING = 0x20,
THERMAL_LIMITATION = 0x40,
SUSPEND_EXIT_VOL_LIMITATION = 0x80,
EXTERNAL_AMP_VOL_FEEDBACK = 0x100,
OTHER = 0x80000000,
}

View file

@ -46,4 +46,6 @@ interface IAudioControl {
oneway void onAudioFocusChangeWithMetaData(in android.hardware.audio.common.PlaybackTrackMetadata playbackMetaData, in int zoneId, in android.hardware.automotive.audiocontrol.AudioFocusChange focusChange);
oneway void setAudioDeviceGainsChanged(in android.hardware.automotive.audiocontrol.Reasons[] reasons, in android.hardware.automotive.audiocontrol.AudioGainConfigInfo[] gains);
oneway void registerGainCallback(in android.hardware.automotive.audiocontrol.IAudioGainCallback callback);
void setModuleChangeCallback(in android.hardware.automotive.audiocontrol.IModuleChangeCallback callback);
void clearModuleChangeCallback();
}

View file

@ -0,0 +1,38 @@
/*
* 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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.audiocontrol;
@VintfStability
interface IModuleChangeCallback {
oneway void onAudioPortsChanged(in android.media.audio.common.AudioPort[] audioPorts);
}

View file

@ -51,6 +51,7 @@ import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
import android.hardware.automotive.audiocontrol.DuckingInfo;
import android.hardware.automotive.audiocontrol.IAudioGainCallback;
import android.hardware.automotive.audiocontrol.IFocusListener;
import android.hardware.automotive.audiocontrol.IModuleChangeCallback;
import android.hardware.automotive.audiocontrol.MutingInfo;
import android.hardware.automotive.audiocontrol.Reasons;
@ -183,4 +184,26 @@ interface IAudioControl {
* interface.
*/
oneway void registerGainCallback(in IAudioGainCallback callback);
/**
* Sets callback with HAL for notifying changes to hardware module (that is:
* {@link android.hardware.audio.core.IModule}) configurations.
*
* @param callback The {@link android.hardware.automotive.audiocontrol.IModuleChangeCallback}
* interface to use use when new updates are available for
* {@link android.hardware.audio.core.IModule} configs
* @throws EX_UNSUPPORTED_OPERATION if dynamic audio configs are not supported.
* @throws EX_ILLEGAL_STATE if a callback already exists
* @throws EX_ILLEGAL_ARGUMENT if the passed callback is (@code null}
*/
void setModuleChangeCallback(in IModuleChangeCallback callback);
/**
* Clears module change callback
*
* If no callback is registered previously, then this call should be a no-op.
*
* @throws EX_UNSUPPORTED_OPERATION if dynamic audio configs are not supported.
*/
void clearModuleChangeCallback();
}

View file

@ -0,0 +1,61 @@
/*
* 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.
*/
package android.hardware.automotive.audiocontrol;
import android.media.audio.common.AudioPort;
/**
* Interface definition for asynchronous changes to audio configs defined
* for a hardware {@link android.hardware.audio.core.IModule}.
*/
@VintfStability
oneway interface IModuleChangeCallback {
/**
* Used to indicate that one or more {@link android.media.audio.common.AudioPort}
* configs have changed. Implementations MUST return at least one AudioPort.
*
* Notes for AudioPort:
* 1. For V3, the support will be limited to configurable AudioGain stages - per
* car audio framework support.
* 2. For automotive 'bus' devices, the expected settings are
* AudioDevice {
* AudioDeviceDescription {type: IN/OUT_DEVICE, connection: CONNECTION_BUS}
* AudioDeviceAddress {id: string}}
*
* Notes for AudioGain:
* 1. Car audio framework only supports AudioGainMode::JOINT. Any other mode
* selection will be ignored.
* See {@link android.media.audio.common.AudioGainMode}
* 2. Implementations MUST ensure that the gain stages are identical for buses
* that map to the same volume group. Any inconsistencies will result in
* inferior volume-change experience to the users.
* 3. Implementations MUST ensure that the new gain stages are subset (do not
* exceed) of the gain stage definitions provided to audio policy. If they
* exceed, it can result in failure when setting value over the range
* allowed by the audio policy.
*
* Other notes:
* 1. In case of AudioControl service restart or resume, the implementations MUST
* issue an immediate callback following registration.
* 2. In case of client restart, the AudioControl service MUST clear all stale
* callbacks.
*
* @param audioPorts list of {@link android.media.audio.common.AudioPort} that
* are updated
*/
void onAudioPortsChanged(in AudioPort[] audioPorts);
}

View file

@ -30,8 +30,8 @@ cc_binary {
shared_libs: [
"android.hardware.audio.common@7.0-enums",
"android.hardware.audio.common-V1-ndk",
"android.frameworks.automotive.powerpolicy-V1-ndk",
"android.hardware.automotive.audiocontrol-V2-ndk",
"android.frameworks.automotive.powerpolicy-V2-ndk",
"android.hardware.automotive.audiocontrol-V3-ndk",
"libbase",
"libbinder_ndk",
"libcutils",

View file

@ -24,6 +24,7 @@
#include <aidl/android/hardware/automotive/audiocontrol/IFocusListener.h>
#include <android-base/logging.h>
#include <android-base/parsebool.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@ -37,6 +38,8 @@
namespace aidl::android::hardware::automotive::audiocontrol {
using ::android::base::EqualsIgnoreCase;
using ::android::base::ParseBool;
using ::android::base::ParseBoolResult;
using ::android::base::ParseInt;
using ::std::shared_ptr;
using ::std::string;
@ -70,6 +73,95 @@ bool safelyParseInt(string s, int* out) {
}
} // namespace
namespace {
using ::aidl::android::media::audio::common::AudioChannelLayout;
using ::aidl::android::media::audio::common::AudioDeviceDescription;
using ::aidl::android::media::audio::common::AudioDeviceType;
using ::aidl::android::media::audio::common::AudioFormatDescription;
using ::aidl::android::media::audio::common::AudioFormatType;
using ::aidl::android::media::audio::common::AudioGain;
using ::aidl::android::media::audio::common::AudioGainMode;
using ::aidl::android::media::audio::common::AudioIoFlags;
using ::aidl::android::media::audio::common::AudioOutputFlags;
using ::aidl::android::media::audio::common::AudioPort;
using ::aidl::android::media::audio::common::AudioPortDeviceExt;
using ::aidl::android::media::audio::common::AudioPortExt;
using ::aidl::android::media::audio::common::AudioPortMixExt;
using ::aidl::android::media::audio::common::AudioProfile;
using ::aidl::android::media::audio::common::PcmType;
// reuse common code artifacts
void fillProfile(const std::vector<int32_t>& channelLayouts,
const std::vector<int32_t>& sampleRates, AudioProfile* profile) {
for (auto layout : channelLayouts) {
profile->channelMasks.push_back(
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
}
profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end());
}
AudioProfile createProfile(PcmType pcmType, const std::vector<int32_t>& channelLayouts,
const std::vector<int32_t>& sampleRates) {
AudioProfile profile;
profile.format.type = AudioFormatType::PCM;
profile.format.pcm = pcmType;
fillProfile(channelLayouts, sampleRates, &profile);
return profile;
}
AudioProfile createProfile(const std::string& encodingType,
const std::vector<int32_t>& channelLayouts,
const std::vector<int32_t>& sampleRates) {
AudioProfile profile;
profile.format.encoding = encodingType;
fillProfile(channelLayouts, sampleRates, &profile);
return profile;
}
AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags,
const std::string& connection = "", const std::string& address = "") {
AudioPortDeviceExt deviceExt;
deviceExt.device.type.type = devType;
if (devType == AudioDeviceType::IN_MICROPHONE && connection.empty()) {
deviceExt.device.address = "bottom";
} else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) {
deviceExt.device.address = "back";
} else {
deviceExt.device.address = std::move(address);
}
deviceExt.device.type.connection = std::move(connection);
deviceExt.flags = flags;
return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
}
AudioPort createPort(int32_t id, const std::string& name, int32_t flags, bool isInput,
const AudioPortExt& ext) {
AudioPort port;
port.id = id;
port.name = name;
port.flags = isInput ? AudioIoFlags::make<AudioIoFlags::Tag::input>(flags)
: AudioIoFlags::make<AudioIoFlags::Tag::output>(flags);
port.ext = ext;
return port;
}
AudioGain createGain(int32_t mode, AudioChannelLayout channelMask, int32_t minValue,
int32_t maxValue, int32_t defaultValue, int32_t stepValue,
int32_t minRampMs = 100, int32_t maxRampMs = 100, bool useForVolume = true) {
AudioGain gain;
gain.mode = mode;
gain.channelMask = channelMask;
gain.minValue = minValue;
gain.maxValue = maxValue;
gain.defaultValue = defaultValue;
gain.stepValue = stepValue;
gain.minRampMs = minRampMs;
gain.maxRampMs = maxRampMs;
gain.useForVolume = useForVolume;
return gain;
}
} // namespace
ndk::ScopedAStatus AudioControl::registerFocusListener(
const shared_ptr<IFocusListener>& in_listener) {
LOG(DEBUG) << "registering focus listener";
@ -190,6 +282,33 @@ ndk::ScopedAStatus AudioControl::registerGainCallback(
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus AudioControl::setModuleChangeCallback(
const std::shared_ptr<IModuleChangeCallback>& in_callback) {
LOG(DEBUG) << ": " << __func__;
if (in_callback.get() == nullptr) {
LOG(ERROR) << __func__ << ": Callback is nullptr";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (mModuleChangeCallback != nullptr) {
LOG(ERROR) << __func__ << ": Module change callback was already registered";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
std::atomic_store(&mModuleChangeCallback, in_callback);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus AudioControl::clearModuleChangeCallback() {
if (mModuleChangeCallback != nullptr) {
shared_ptr<IModuleChangeCallback> nullCallback = nullptr;
std::atomic_store(&mModuleChangeCallback, nullCallback);
LOG(DEBUG) << ":" << __func__ << ": Unregistered successfully";
} else {
LOG(DEBUG) << ":" << __func__ << ": No callback registered, no-op";
}
return ndk::ScopedAStatus::ok();
}
binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) {
if (numArgs == 0) {
return dumpsys(fd);
@ -208,6 +327,8 @@ binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs)
return cmdAbandonFocusWithMetaData(fd, args, numArgs);
} else if (EqualsIgnoreCase(option, "--audioGainCallback")) {
return cmdOnAudioDeviceGainsChanged(fd, args, numArgs);
} else if (EqualsIgnoreCase(option, "--audioPortsChangedCallback")) {
return cmdOnAudioPortsChanged(fd, args, numArgs);
} else {
dprintf(fd, "Invalid option: %s\n", option.c_str());
return STATUS_BAD_VALUE;
@ -262,7 +383,21 @@ binder_status_t AudioControl::cmdHelp(int fd) const {
dprintf(fd,
"Tags are optional. If provided, it must follow the <key>=<value> pattern, where the "
"value is namespaced (for example com.google.strategy=VR).\n");
dprintf(fd,
"--audioPortsChangedCallback <ID_1> <NAME_1> <BUS_ADDRESS_1> <CONNECTION_TYPE_1> "
"<AUDIO_GAINS_1> [<ID_N> <NAME_N> <BUS_ADDRESS_N> <CONNECTION_TYPE_N> "
"<AUDIO_GAINS_N>]: fires audio ports changed callback. Carries list of modified "
"AudioPorts. "
"For simplicity, this command accepts limited information for each AudioPort: "
"id(int), name(string), port address(string), connection type (string), "
"audio gain (csv int)\n");
dprintf(fd, "Notes: \n");
dprintf(fd,
"1. AudioGain csv should match definition at "
"android/media/audio/common/AudioPort.aidl\n");
dprintf(fd,
"2. See android/media/audio/common/AudioDeviceDescription.aidl for valid "
"<CONNECTION_TYPE> values.\n");
return STATUS_OK;
}
@ -514,4 +649,166 @@ binder_status_t AudioControl::cmdOnAudioDeviceGainsChanged(int fd, const char**
toEnumString(reasons).c_str(), toString(agcis).c_str());
return STATUS_OK;
}
binder_status_t AudioControl::parseAudioGains(int fd, const std::string& stringGain,
std::vector<AudioGain>& gains) {
const int kAudioGainSize = 9;
std::stringstream csvGain(stringGain);
std::vector<std::string> vecGain;
std::string value;
while (getline(csvGain, value, ',')) {
vecGain.push_back(value);
}
if ((vecGain.size() == 0) || ((vecGain.size() % kAudioGainSize) != 0)) {
dprintf(fd, "Erroneous input to generate AudioGain: %s\n", stringGain.c_str());
return STATUS_BAD_VALUE;
}
// iterate over injected AudioGains
for (int index = 0; index < vecGain.size(); index += kAudioGainSize) {
int32_t mode;
if (!safelyParseInt(vecGain[index], &mode)) {
dprintf(fd, "Non-integer index provided with request: %s\n", vecGain[index].c_str());
return STATUS_BAD_VALUE;
}
// car audio framework only supports JOINT mode.
// skip injected AudioGains that are not compliant with this.
if (mode != static_cast<int>(AudioGainMode::JOINT)) {
LOG(WARNING) << ":" << __func__ << ": skipping gain since it is not JOINT mode!";
continue;
}
int32_t layout;
if (!safelyParseInt(vecGain[index + 1], &layout)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 1].c_str());
return STATUS_BAD_VALUE;
}
AudioChannelLayout channelMask =
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout);
int32_t minValue;
if (!safelyParseInt(vecGain[index + 2], &minValue)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 2].c_str());
return STATUS_BAD_VALUE;
}
int32_t maxValue;
if (!safelyParseInt(vecGain[index + 3], &maxValue)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 3].c_str());
return STATUS_BAD_VALUE;
}
int32_t defaultValue;
if (!safelyParseInt(vecGain[index + 4], &defaultValue)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 4].c_str());
return STATUS_BAD_VALUE;
}
int32_t stepValue;
if (!safelyParseInt(vecGain[index + 5], &stepValue)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 5].c_str());
return STATUS_BAD_VALUE;
}
int32_t minRampMs;
if (!safelyParseInt(vecGain[index + 6], &minRampMs)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 6].c_str());
return STATUS_BAD_VALUE;
}
int32_t maxRampMs;
if (!safelyParseInt(vecGain[index + 7], &maxRampMs)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
vecGain[index + 7].c_str());
return STATUS_BAD_VALUE;
}
ParseBoolResult useForVolume = ParseBool(vecGain[index + 8]);
if (useForVolume == ParseBoolResult::kError) {
dprintf(fd, "Non-boolean index provided with request: %s\n",
vecGain[index + 8].c_str());
return STATUS_BAD_VALUE;
} else if (useForVolume == ParseBoolResult::kFalse) {
// at this level we only care about gain stages that are relevant
// for volume control. skip the gain stage if its flagged as false.
LOG(WARNING) << ":" << __func__
<< ": skipping gain since it is not for volume control!";
continue;
}
AudioGain gain = createGain(mode, channelMask, minValue, maxValue, defaultValue, stepValue,
minRampMs, maxRampMs, true /*useForVolume*/);
gains.push_back(gain);
}
return STATUS_OK;
}
binder_status_t AudioControl::cmdOnAudioPortsChanged(int fd, const char** args, uint32_t numArgs) {
if (!checkCallerHasWritePermissions(fd)) {
return STATUS_PERMISSION_DENIED;
}
if ((numArgs < 6) || ((numArgs - 1) % 5 != 0)) {
dprintf(fd,
"Invalid number of arguments: please provide\n"
"--audioPortsChangedCallback <ID_1> <NAME_1> <BUS_ADDRESS_1> <CONNECTION_TYPE_1> "
"<AUDIO_GAINS_1> [<ID_N> <NAME_N> <BUS_ADDRESS_N> <CONNECTION_TYPE_N> "
"<AUDIO_GAINS_N>]: triggers audio ports changed callback. Carries list of "
"modified AudioPorts. "
"For simplicity, this command accepts limited information for each AudioPort: "
"id(int), name(string), port address(string), connection type (string), "
"audio gain (csv int)\n");
return STATUS_BAD_VALUE;
}
std::vector<AudioPort> ports;
for (uint32_t i = 1; i < numArgs; i += 5) {
binder_status_t status;
int32_t id;
if (!safelyParseInt(std::string(args[i]), &id)) {
dprintf(fd, "Non-integer index provided with request: %s\n",
std::string(args[i]).c_str());
return STATUS_BAD_VALUE;
}
std::string name = std::string(args[i + 1]);
std::string address = std::string(args[i + 2]);
std::string connection = std::string(args[i + 3]);
std::string stringGains = std::string(args[i + 4]);
std::vector<AudioGain> gains;
status = parseAudioGains(fd, stringGains, gains);
if (status != STATUS_OK) {
return status;
}
AudioPort port = createPort(
id, name, 0 /*flags*/, false /*isInput*/,
createDeviceExt(AudioDeviceType::OUT_DEVICE, 0 /*flags*/, connection, address));
port.gains.insert(port.gains.begin(), gains.begin(), gains.end());
ports.push_back(port);
}
if (mModuleChangeCallback == nullptr) {
dprintf(fd,
"Unable to trigger audio port callback for ports: %s \n"
" - no module change callback registered\n",
toString(ports).c_str());
return STATUS_BAD_VALUE;
}
// TODO (b/269139706) fix atomic read issue
mModuleChangeCallback->onAudioPortsChanged(ports);
dprintf(fd, "SUCCESS audio port callback for ports: %s \n", toString(ports).c_str());
return STATUS_OK;
}
} // namespace aidl::android::hardware::automotive::audiocontrol

View file

@ -21,11 +21,20 @@
#include <aidl/android/hardware/automotive/audiocontrol/BnAudioControl.h>
#include <aidl/android/hardware/automotive/audiocontrol/DuckingInfo.h>
#include <aidl/android/hardware/automotive/audiocontrol/IAudioGainCallback.h>
#include <aidl/android/hardware/automotive/audiocontrol/IModuleChangeCallback.h>
#include <aidl/android/hardware/automotive/audiocontrol/MutingInfo.h>
#include <aidl/android/hardware/automotive/audiocontrol/Reasons.h>
#include <aidl/android/hardware/audio/common/PlaybackTrackMetadata.h>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
#include <aidl/android/media/audio/common/AudioFormatType.h>
#include <aidl/android/media/audio/common/AudioGainMode.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
namespace aidl::android::hardware::automotive::audiocontrol {
namespace audiohalcommon = ::aidl::android::hardware::audio::common;
@ -51,6 +60,9 @@ class AudioControl : public BnAudioControl {
const std::vector<AudioGainConfigInfo>& in_gains) override;
ndk::ScopedAStatus registerGainCallback(
const std::shared_ptr<IAudioGainCallback>& in_callback) override;
ndk::ScopedAStatus setModuleChangeCallback(
const std::shared_ptr<IModuleChangeCallback>& in_callback) override;
ndk::ScopedAStatus clearModuleChangeCallback() override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
@ -67,15 +79,23 @@ class AudioControl : public BnAudioControl {
*/
std::shared_ptr<IAudioGainCallback> mAudioGainCallback = nullptr;
std::shared_ptr<IModuleChangeCallback> mModuleChangeCallback = nullptr;
binder_status_t cmdHelp(int fd) const;
binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs);
binder_status_t cmdAbandonFocus(int fd, const char** args, uint32_t numArgs);
binder_status_t cmdRequestFocusWithMetaData(int fd, const char** args, uint32_t numArgs);
binder_status_t cmdAbandonFocusWithMetaData(int fd, const char** args, uint32_t numArgs);
binder_status_t cmdOnAudioDeviceGainsChanged(int fd, const char** args, uint32_t numArgs);
binder_status_t cmdOnAudioPortsChanged(int fd, const char** args, uint32_t numArgs);
binder_status_t parseMetaData(int fd, const std::string& metadataLiteral,
audiohalcommon::PlaybackTrackMetadata& trackMetadata);
binder_status_t parseAudioGains(
int fd, const std::string& stringGain,
std::vector<::aidl::android::media::audio::common::AudioGain>& gains);
binder_status_t parseSampleRates(int fd, const std::string& sampleRates,
std::vector<int32_t>& vecSampleRates);
binder_status_t dumpsys(int fd);
};

View file

@ -1,7 +1,7 @@
<manifest version="2.0" type="device">
<hal format="aidl">
<version>2</version>
<name>android.hardware.automotive.audiocontrol</name>
<version>3</version>
<fqname>IAudioControl/default</fqname>
</hal>
</manifest>

View file

@ -38,8 +38,8 @@ cc_test {
"libxml2",
],
static_libs: [
"android.hardware.automotive.audiocontrol-V3-cpp",
"android.hardware.audio.common-V1-cpp",
"android.hardware.automotive.audiocontrol-V2-cpp",
"libgmock",
],
test_suites: [

View file

@ -21,6 +21,7 @@
#include <android/hardware/automotive/audiocontrol/BnAudioGainCallback.h>
#include <android/hardware/automotive/audiocontrol/BnFocusListener.h>
#include <android/hardware/automotive/audiocontrol/BnModuleChangeCallback.h>
#include <android/hardware/automotive/audiocontrol/IAudioControl.h>
#include <android/log.h>
#include <binder/IServiceManager.h>
@ -34,10 +35,14 @@ using android::hardware::automotive::audiocontrol::AudioFocusChange;
using android::hardware::automotive::audiocontrol::AudioGainConfigInfo;
using android::hardware::automotive::audiocontrol::BnAudioGainCallback;
using android::hardware::automotive::audiocontrol::BnFocusListener;
using android::hardware::automotive::audiocontrol::BnModuleChangeCallback;
using android::hardware::automotive::audiocontrol::DuckingInfo;
using android::hardware::automotive::audiocontrol::IAudioControl;
using android::hardware::automotive::audiocontrol::IModuleChangeCallback;
using android::hardware::automotive::audiocontrol::MutingInfo;
using android::hardware::automotive::audiocontrol::Reasons;
using ::testing::AnyOf;
using ::testing::Eq;
#include "android_audio_policy_configuration_V7_0.h"
@ -48,15 +53,25 @@ using namespace android::audio::policy::configuration::V7_0;
namespace audiohalcommon = android::hardware::audio::common;
namespace audiomediacommon = android::media::audio::common;
namespace {
constexpr int32_t kAidlVersionThree = 3;
}
class AudioControlAidl : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
audioControl = android::waitForDeclaredService<IAudioControl>(String16(GetParam().c_str()));
ASSERT_NE(audioControl, nullptr);
aidlVersion = audioControl->getInterfaceVersion();
}
void TearDown() override { audioControl = nullptr; }
bool isAidlVersionAtleast(int version) const { return aidlVersion >= version; }
sp<IAudioControl> audioControl;
int32_t capabilities;
int32_t aidlVersion;
};
TEST_P(AudioControlAidl, OnSetFadeTowardsFront) {
@ -226,6 +241,57 @@ TEST_P(AudioControlAidl, AudioGainCallbackRegistration) {
ASSERT_TRUE(audioControl->registerGainCallback(gainCallback2).isOk());
}
/*
* Test Module change Callback registration.
*
* Verifies that:
* - setModuleChangeCallback succeeds
* - setting a double callback fails with exception
* - clearModuleChangeCallback succeeds
* - setting with nullptr callback fails with exception
* - closing handle does not crash
*/
struct ModuleChangeCallbackMock : BnModuleChangeCallback {
MOCK_METHOD(Status, onAudioPortsChanged,
(const std::vector<android::media::audio::common::AudioPort>& audioPorts));
};
TEST_P(AudioControlAidl, RegisterModuleChangeCallbackTwiceThrowsException) {
ALOGI("Register Module change callback test");
if (!isAidlVersionAtleast(kAidlVersionThree)) {
GTEST_SKIP() << "Device does not support the new APIs for module change callback";
return;
}
// make sure no stale callbacks.
audioControl->clearModuleChangeCallback();
sp<ModuleChangeCallbackMock> moduleChangeCallback = new ModuleChangeCallbackMock();
auto status = audioControl->setModuleChangeCallback(moduleChangeCallback);
EXPECT_THAT(status.exceptionCode(),
AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION)));
if (!status.isOk()) return;
sp<ModuleChangeCallbackMock> moduleChangeCallback2 = new ModuleChangeCallbackMock();
// no need to check for unsupported feature
EXPECT_EQ(Status::EX_ILLEGAL_STATE,
audioControl->setModuleChangeCallback(moduleChangeCallback2).exceptionCode());
ASSERT_TRUE(audioControl->clearModuleChangeCallback().isOk());
ASSERT_TRUE(audioControl->setModuleChangeCallback(moduleChangeCallback2).isOk());
}
TEST_P(AudioControlAidl, RegisterModuleChangeNullCallbackThrowsException) {
ALOGI("Register Module change callback with nullptr test");
if (!isAidlVersionAtleast(kAidlVersionThree)) {
GTEST_SKIP() << "Device does not support the new APIs for module change callback";
return;
}
auto status = audioControl->setModuleChangeCallback(nullptr);
EXPECT_THAT(status.exceptionCode(),
AnyOf(Eq(Status::EX_ILLEGAL_ARGUMENT), Eq(Status::EX_UNSUPPORTED_OPERATION)));
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl);
INSTANTIATE_TEST_SUITE_P(
Audiocontrol, AudioControlAidl,

View file

@ -80,7 +80,7 @@ bool setBitrate(std::string ifname, uint32_t bitrate) {
{
auto linkinfo = req.addNested(IFLA_LINKINFO);
req.add(IFLA_INFO_KIND, "can");
req.addBuffer(IFLA_INFO_KIND, "can");
{
auto infodata = req.addNested(IFLA_INFO_DATA);
/* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING

View file

@ -47,7 +47,7 @@ static SocketParams getSocketParams(int domain) {
return params;
}
bool send(unsigned long request, struct ifreq& ifr) {
int trySend(unsigned long request, struct ifreq& ifr) {
const auto sp = getSocketParams(socketDomain);
base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol));
if (!sock.ok()) {
@ -55,7 +55,12 @@ bool send(unsigned long request, struct ifreq& ifr) {
return false;
}
if (ioctl(sock.get(), request, &ifr) < 0) {
if (ioctl(sock.get(), request, &ifr) < 0) return errno;
return 0;
}
bool send(unsigned long request, struct ifreq& ifr) {
if (trySend(request, ifr) != 0) {
PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
return false;
}

View file

@ -27,6 +27,15 @@ namespace android::netdevice::ifreqs {
*/
extern std::atomic_int socketDomain;
/**
* Tries to send ioctl interface request.
*
* \param request Request type (such as SIOCGIFFLAGS)
* \param ifr Request data (both input and output)
* \return error code of the call (0 for success)
*/
int trySend(unsigned long request, struct ifreq& ifr);
/**
* Sends ioctl interface request.
*

View file

@ -67,21 +67,33 @@ enum class WaitCondition {
*/
PRESENT_AND_UP,
/**
* Interface is up and with IPv4 address configured.
*/
PRESENT_AND_IPV4,
/**
* Interface is down or not present (disconnected) at all.
*/
DOWN_OR_GONE,
};
enum class Quantifier {
ALL_OF,
ANY_OF,
};
/**
* Listens for interface changes until anticipated condition takes place.
*
* \param ifnames List of interfaces to watch for.
* \param cnd Awaited condition.
* \param allOf true if all interfaces need to satisfy the condition, false if only one satistying
* \param quant Whether all interfaces need to satisfy the condition or just one satistying
* interface should stop the wait.
* \return name of one interface that satisfied the condition
*/
void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true);
std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd,
Quantifier quant = Quantifier::ALL_OF);
/**
* Brings network interface up.

View file

@ -60,7 +60,7 @@ bool add(std::string dev, std::string type) {
{
auto linkinfo = req.addNested(IFLA_LINKINFO);
req.add(IFLA_INFO_KIND, type);
req.addBuffer(IFLA_INFO_KIND, type);
}
nl::Socket sock(NETLINK_ROUTE);
@ -100,23 +100,36 @@ std::optional<bool> isUp(std::string ifname) {
return ifr.ifr_flags & IFF_UP;
}
static bool hasIpv4(std::string ifname) {
auto ifr = ifreqs::fromName(ifname);
switch (const auto status = ifreqs::trySend(SIOCGIFADDR, ifr)) {
case 0:
return true;
case EADDRNOTAVAIL:
case ENODEV:
return false;
default:
PLOG(WARNING) << "Failed checking IPv4 address";
return false;
}
}
struct WaitState {
bool present;
bool up;
bool hasIpv4Addr;
bool satisfied(WaitCondition cnd) const {
switch (cnd) {
case WaitCondition::PRESENT:
if (present) return true;
break;
return present;
case WaitCondition::PRESENT_AND_UP:
if (present && up) return true;
break;
return present && up;
case WaitCondition::PRESENT_AND_IPV4:
return present && up && hasIpv4Addr;
case WaitCondition::DOWN_OR_GONE:
if (!present || !up) return true;
break;
return !present || !up;
}
return false;
}
};
@ -126,11 +139,22 @@ static std::string toString(WaitCondition cnd) {
return "become present";
case WaitCondition::PRESENT_AND_UP:
return "come up";
case WaitCondition::PRESENT_AND_IPV4:
return "get IPv4 address";
case WaitCondition::DOWN_OR_GONE:
return "go down";
}
}
static std::string toString(Quantifier quant) {
switch (quant) {
case Quantifier::ALL_OF:
return "all of";
case Quantifier::ANY_OF:
return "any of";
}
}
static std::string toString(const std::set<std::string>& ifnames) {
std::stringstream ss;
std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
@ -139,50 +163,73 @@ static std::string toString(const std::set<std::string>& ifnames) {
return str;
}
void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) {
nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd,
Quantifier quant) {
nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
using StatesMap = std::map<std::string, WaitState>;
StatesMap states = {};
for (const auto ifname : ifnames) {
const auto present = exists(ifname);
const auto up = present && isUp(ifname).value_or(false);
states[ifname] = {present, up};
const auto hasIpv4Addr = present && hasIpv4(ifname);
states[ifname] = {present, up, hasIpv4Addr};
}
const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
return it.second.satisfied(cnd);
};
const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() {
if (allOf) {
return std::all_of(states.begin(), states.end(), mapConditionChecker);
} else {
return std::any_of(states.begin(), states.end(), mapConditionChecker);
const auto isFullySatisfied = [&states, quant,
mapConditionChecker]() -> std::optional<std::string> {
if (quant == Quantifier::ALL_OF) {
if (!std::all_of(states.begin(), states.end(), mapConditionChecker)) return {};
return states.begin()->first;
} else { // Quantifier::ANY_OF
const auto it = std::find_if(states.begin(), states.end(), mapConditionChecker);
if (it == states.end()) return {};
return it->first;
}
};
if (isFullySatisfied()) return;
if (const auto iface = isFullySatisfied()) return iface;
LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to "
LOG(DEBUG) << "Waiting for " << toString(quant) << " " << toString(ifnames) << " to "
<< toString(cnd);
for (const auto rawMsg : sock) {
const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
if (!msg.has_value()) continue;
if (const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
msg.has_value()) {
// Interface added / removed
const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
if (ifnames.count(ifname) == 0) continue;
const bool present = (msg->header.nlmsg_type != RTM_DELLINK);
const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0;
states[ifname] = {present, up};
auto& state = states[ifname];
state.present = (msg->header.nlmsg_type != RTM_DELLINK);
state.up = state.present && (msg->data.ifi_flags & IFF_UP) != 0;
if (!state.present) state.hasIpv4Addr = false;
if (isFullySatisfied()) {
LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
} else if (const auto msg =
nl::Message<ifaddrmsg>::parse(rawMsg, {RTM_NEWADDR, RTM_DELADDR});
msg.has_value()) {
// Address added / removed
const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
if (ifnames.count(ifname) == 0) continue;
if (msg->header.nlmsg_type == RTM_NEWADDR) {
states[ifname].hasIpv4Addr = true;
} else {
// instead of tracking which one got deleted, let's just ask
states[ifname].hasIpv4Addr = hasIpv4(ifname);
}
}
if (const auto iface = isFullySatisfied()) {
LOG(DEBUG) << "Finished waiting for " << toString(quant) << " " << toString(ifnames)
<< " to " << toString(cnd);
return;
return iface;
}
}
LOG(FATAL) << "Can't read Netlink socket";
return {};
}
} // namespace android::netdevice

View file

@ -40,7 +40,7 @@ bool add(const std::string& eth, const std::string& vlan, uint16_t id) {
{
auto linkinfo = req.addNested(IFLA_LINKINFO);
req.add(IFLA_INFO_KIND, "vlan");
req.addBuffer(IFLA_INFO_KIND, "vlan");
{
auto linkinfo = req.addNested(IFLA_INFO_DATA);

View file

@ -37,8 +37,10 @@ cc_library_static {
"protocols/generic/Unknown.cpp",
"protocols/generic/families/Mac80211hwsim.cpp",
"protocols/generic/families/Nl80211.cpp",
"protocols/route/Addr.cpp",
"protocols/route/Link.cpp",
"protocols/route/Route.cpp",
"protocols/route/attributes.cpp",
"protocols/route/structs.cpp",
"protocols/MessageDefinition.cpp",
"protocols/NetlinkProtocol.cpp",

View file

@ -27,8 +27,8 @@ static nlattr* tail(nlmsghdr* msg) {
nlattr* MessageFactoryBase::add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
size_t dataLen) {
const auto totalAttrLen = impl::space<nlattr>(dataLen);
const auto newLen = impl::align(msg->nlmsg_len) + totalAttrLen;
const auto totalAttrLen = impl::length<nlattr>(dataLen);
const auto newLen = impl::align(msg->nlmsg_len) + impl::align(totalAttrLen);
if (newLen > maxLen) {
LOG(ERROR) << "Can't add attribute of size " << dataLen //
<< " - exceeded maxLen: " << newLen << " > " << maxLen;

View file

@ -47,6 +47,17 @@ Socket::Socket(int protocol, unsigned pid, uint32_t groups) : mProtocol(protocol
}
}
void Socket::clearPollErr() {
sockaddr_nl sa = {};
socklen_t saLen = sizeof(sa);
const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), mReceiveBuffer.size(), 0,
reinterpret_cast<sockaddr*>(&sa), &saLen);
if (errno != EINVAL) {
PLOG(WARNING) << "clearPollError() caught unexpected error: ";
}
CHECK_LE(bytesReceived, 0) << "clearPollError() didn't find an error!";
}
bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
if constexpr (kSuperVerbose) {
LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
@ -110,6 +121,13 @@ std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size
if constexpr (kSuperVerbose) {
LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
}
long headerByteTotal = 0;
for (const auto hdr : msg) {
headerByteTotal += hdr->nlmsg_len;
}
if (bytesReceived != headerByteTotal) {
LOG(ERROR) << "received " << bytesReceived << " bytes, header claims " << headerByteTotal;
}
return {msg, sa};
}
@ -159,6 +177,7 @@ std::optional<unsigned> Socket::getPid() {
}
pollfd Socket::preparePoll(short events) {
CHECK(mFd.get() > 0) << "Netlink socket fd is invalid!";
return {mFd.get(), events, 0};
}

View file

@ -106,18 +106,25 @@ class MessageFactory : private MessageFactoryBase {
*/
template <class A>
void add(nlattrtype_t type, const A& attr) {
add(type, &attr, sizeof(attr));
addInternal(type, &attr, sizeof(attr));
}
// It will always send the last null character, otherwise use addBuffer
// variant instead
template <>
void add(nlattrtype_t type, const std::string& s) {
add(type, s.c_str(), s.size() + 1);
addInternal(type, s.c_str(), s.size() + 1);
}
void addBuffer(nlattrtype_t type, const std::string_view& s) {
addInternal(type, s.data(), s.size());
}
/** Guard class to frame nested attributes. \see addNested(nlattrtype_t). */
class [[nodiscard]] NestedGuard {
public:
NestedGuard(MessageFactory & req, nlattrtype_t type) : mReq(req), mAttr(req.add(type)) {}
NestedGuard(MessageFactory& req, nlattrtype_t type)
: mReq(req), mAttr(req.addInternal(type)) {}
~NestedGuard() { closeNested(&mReq.mMessage.header, mAttr); }
private:
@ -138,7 +145,7 @@ class MessageFactory : private MessageFactoryBase {
* MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
* {
* auto linkinfo = req.addNested(IFLA_LINKINFO);
* req.add(IFLA_INFO_KIND, "can");
* req.addBuffer(IFLA_INFO_KIND, "can");
* {
* auto infodata = req.addNested(IFLA_INFO_DATA);
* req.add(IFLA_CAN_BITTIMING, bitTimingStruct);
@ -154,7 +161,7 @@ class MessageFactory : private MessageFactoryBase {
Message mMessage = {};
bool mIsGood = true;
nlattr* add(nlattrtype_t type, const void* data = nullptr, size_t len = 0) {
nlattr* addInternal(nlattrtype_t type, const void* data = nullptr, size_t len = 0) {
if (!mIsGood) return nullptr;
auto attr = MessageFactoryBase::add(&mMessage.header, sizeof(mMessage), type, data, len);
if (attr == nullptr) mIsGood = false;

View file

@ -54,6 +54,12 @@ class Socket {
*/
Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
/**
* Attempt to clear POLLERR by recv-ing.
* TODO(224850481): determine if this is necessary, or if the socket is locked up anyway.
*/
void clearPollErr();
/**
* Send Netlink message with incremented sequence number to the Kernel.
*

View file

@ -35,12 +35,20 @@ constexpr size_t align(size_t len) {
return (len + alignto - 1) & ~(alignto - 1);
}
/**
* Equivalent to NLMSG_LENGTH(len).
*/
template <typename H>
constexpr size_t length(size_t len) {
return align(sizeof(H)) + len;
}
/**
* Equivalent to NLMSG_SPACE(len).
*/
template <typename H>
constexpr size_t space(size_t len) {
return align(align(sizeof(H)) + len);
return align(length<H>(len));
}
/**

View file

@ -34,7 +34,7 @@ const AttributeDefinition AttributeMap::operator[](nlattrtype_t nla_type) const
MessageDescriptor::MessageDescriptor(const std::string& name,
const MessageDetailsMap&& messageDetails,
const AttributeMap&& attrTypes, size_t contentsSize)
const AttributeMap& attrTypes, size_t contentsSize)
: mName(name),
mContentsSize(contentsSize),
mMessageDetails(messageDetails),

View file

@ -163,7 +163,7 @@ class MessageDescriptor {
protected:
MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
const AttributeMap&& attrTypes, size_t contentsSize);
const AttributeMap& attrTypes, size_t contentsSize);
private:
const std::string mName;
@ -183,7 +183,7 @@ class MessageDefinition : public MessageDescriptor {
MessageDefinition( //
const std::string& name,
const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
const std::initializer_list<AttributeMap::value_type> attrTypes = {})
const AttributeMap& attrTypes = {})
: MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {

View file

@ -33,12 +33,12 @@ static std::map<int, std::shared_ptr<NetlinkProtocol>> toMap(
return map;
}
static auto all = toMap({
std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol) {
static auto all = toMap({
std::make_unique<generic::Generic>(),
std::make_unique<route::Route>(),
});
});
std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol) {
if (all.count(protocol) == 0) return std::nullopt;
return *all.find(protocol)->second.get();
}

View file

@ -30,6 +30,7 @@ bool FamilyTracker::track(const Buffer<nlmsghdr>& buffer) {
const auto familyName = msg.attributes.get<std::string>(CTRL_ATTR_FAMILY_NAME);
const auto familyId = msg.attributes.get<uint16_t>(CTRL_ATTR_FAMILY_ID);
// TODO(224845900): NETLINK_GENERIC == 16, and (erroneously?) sets off this warning
if (familyId < GENL_START_ALLOC) {
LOG(WARNING) << "Invalid family ID: " << familyId;
return true;

View file

@ -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.
*/
#include "Addr.h"
#include "../structs.h"
#include "attributes.h"
#include "structs.h"
namespace android::nl::protocols::route {
using DataType = AttributeDefinition::DataType;
// clang-format off
Addr::Addr() : MessageDefinition<ifaddrmsg>("addr", {
{RTM_NEWADDR, {"NEWADDR", MessageGenre::New}},
{RTM_DELADDR, {"DELADDR", MessageGenre::Delete}},
{RTM_GETADDR, {"GETADDR", MessageGenre::Get}},
}, gAttributes) {}
static const FlagsMap ifaFlagsMap {
{IFA_F_SECONDARY, "SECONDARY"},
{IFA_F_NODAD, "NODAD"},
{IFA_F_OPTIMISTIC, "OPTIMISTIC"},
{IFA_F_DADFAILED, "DADFAILED"},
{IFA_F_HOMEADDRESS, "HOMEADDRESS"},
{IFA_F_DEPRECATED, "DEPRECATED"},
{IFA_F_TENTATIVE, "TENTATIVE"},
{IFA_F_PERMANENT, "PERMANENT"},
{IFA_F_MANAGETEMPADDR, "MANAGETEMPADDR"},
{IFA_F_NOPREFIXROUTE, "NOPREFIXROUTE"},
{IFA_F_MCAUTOJOIN, "MCAUTOJOIN"},
{IFA_F_STABLE_PRIVACY, "STABLE_PRIVACY"},
};
// clang-format on
void Addr::toStream(std::stringstream& ss, const ifaddrmsg& data) const {
ss << "ifaddrmsg{"
<< "family=" << familyToString(data.ifa_family)
<< ", prefixlen=" << unsigned(data.ifa_prefixlen) << ", flags=";
flagsToStream(ss, ifaFlagsMap, data.ifa_flags);
ss << ", scope=" << unsigned(data.ifa_scope) << ", index=" << data.ifa_index << "}";
}
} // namespace android::nl::protocols::route

View file

@ -0,0 +1,31 @@
/*
* 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.
*/
#pragma once
#include "../MessageDefinition.h"
#include <linux/rtnetlink.h>
namespace android::nl::protocols::route {
class Addr : public MessageDefinition<ifaddrmsg> {
public:
Addr();
void toStream(std::stringstream& ss, const ifaddrmsg& data) const override;
};
} // namespace android::nl::protocols::route

View file

@ -16,10 +16,7 @@
#include "Link.h"
#include "../structs.h"
#include "structs.h"
#include <net/if.h>
#include "attributes.h"
namespace android::nl::protocols::route {
@ -30,83 +27,8 @@ Link::Link() : MessageDefinition<ifinfomsg>("link", {
{RTM_NEWLINK, {"NEWLINK", MessageGenre::New}},
{RTM_DELLINK, {"DELLINK", MessageGenre::Delete}},
{RTM_GETLINK, {"GETLINK", MessageGenre::Get}},
}, {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
{IFLA_IFNAME, {"IFNAME", DataType::String}},
{IFLA_MTU, {"MTU", DataType::Uint}},
{IFLA_LINK, {"LINK", DataType::Uint}},
{IFLA_QDISC, {"QDISC", DataType::String}},
{IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
{IFLA_COST, {"COST"}},
{IFLA_PRIORITY, {"PRIORITY"}},
{IFLA_MASTER, {"MASTER", DataType::Uint}},
{IFLA_WIRELESS, {"WIRELESS"}},
{IFLA_PROTINFO, {"PROTINFO"}},
{IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
{IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
{IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
{IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
{IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
{IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
{IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
{IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
{IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
{IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
{IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
}}},
{IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
{IFLA_IFALIAS, {"IFALIAS", DataType::String}},
{IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
{IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
{IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
{IFLA_VF_PORTS, {"VF_PORTS"}},
{IFLA_PORT_SELF, {"PORT_SELF"}},
{IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
{AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
{IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
}}},
{AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
{IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
{IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
{IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_MCAST, {"INET6_MCAST"}},
{IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
{IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
{IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
}}},
}}},
{IFLA_GROUP, {"GROUP", DataType::Uint}},
{IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
{IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
{IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
{IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
{IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
{IFLA_CARRIER, {"CARRIER", DataType::Uint}},
{IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
{IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
{IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
{IFLA_LINK_NETNSID, {"LINK_NETNSID"}}, // NLA_S32
{IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
{IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
{IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
{IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
{IFLA_PAD, {"PAD"}},
{IFLA_XDP, {"XDP"}},
{IFLA_EVENT, {"EVENT", DataType::Uint}},
{IFLA_NEW_NETNSID, {"NEW_NETNSID"}}, // NLA_S32
{IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}}, // NLA_S32
{IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
{IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
{IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}}, // NLA_S32
{IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
{IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
{IFLA_PROP_LIST, {"PROP_LIST"}},
{IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
{IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
}) {}
// clang-format off
}, gAttributes) {}
// clang-format on
void Link::toStream(std::stringstream& ss, const ifinfomsg& data) const {
ss << "ifinfomsg{"

View file

@ -16,10 +16,16 @@
#include "Route.h"
#include "Addr.h"
#include "Link.h"
namespace android::nl::protocols::route {
Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {std::make_shared<Link>()}) {}
// clang-format off
Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {
std::make_shared<Addr>(),
std::make_shared<Link>(),
}) {}
// clang-format on
} // namespace android::nl::protocols::route

View file

@ -0,0 +1,109 @@
/*
* 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 "attributes.h"
#include "../structs.h"
#include "structs.h"
#include <linux/rtnetlink.h>
#include <net/if.h>
namespace android::nl::protocols::route {
using DataType = AttributeDefinition::DataType;
using Flags = AttributeDefinition::Flags;
// clang-format off
AttributeMap gAttributes = {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
{IFLA_IFNAME, {"IFNAME", DataType::StringNul}},
{IFLA_MTU, {"MTU", DataType::Uint}},
{IFLA_LINK, {"LINK", DataType::Uint}},
{IFLA_QDISC, {"QDISC", DataType::Raw, AttributeMap{}, Flags::Verbose}}, // should be DataType::String, but looks like binary blob
{IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
{IFLA_COST, {"COST", DataType::Uint}},
{IFLA_PRIORITY, {"PRIORITY"}},
{IFLA_MASTER, {"MASTER", DataType::Uint}},
{IFLA_WIRELESS, {"WIRELESS"}},
{IFLA_PROTINFO, {"PROTINFO"}},
{IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
{IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
{IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
{IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
{IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
{IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
{IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
{IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
{IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
{IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
{IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
}}},
{IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
{IFLA_IFALIAS, {"IFALIAS", DataType::String}},
{IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
{IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
{IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
{IFLA_VF_PORTS, {"VF_PORTS"}},
{IFLA_PORT_SELF, {"PORT_SELF"}},
{IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
{AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
{IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
}}},
{AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
{IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
{IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
{IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_MCAST, {"INET6_MCAST"}},
{IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
{IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
{IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
}}},
}}},
{IFLA_GROUP, {"GROUP", DataType::Uint}},
{IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
{IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
{IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
{IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
{IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
{IFLA_CARRIER, {"CARRIER", DataType::Uint}},
{IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
{IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
{IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
{IFLA_LINK_NETNSID, {"LINK_NETNSID"}}, // NLA_S32
{IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
{IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
{IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
{IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
{IFLA_PAD, {"PAD"}},
{IFLA_XDP, {"XDP"}},
{IFLA_EVENT, {"EVENT", DataType::Uint}},
{IFLA_NEW_NETNSID, {"NEW_NETNSID"}}, // NLA_S32
{IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}}, // NLA_S32
{IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
{IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
{IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}}, // NLA_S32
{IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
{IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
{IFLA_PROP_LIST, {"PROP_LIST"}},
{IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
{IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
};
// clang-format on
} // namespace android::nl::protocols::route

View file

@ -0,0 +1,25 @@
/*
* 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.
*/
#pragma once
#include "../MessageDefinition.h"
namespace android::nl::protocols::route {
extern AttributeMap gAttributes;
} // namespace android::nl::protocols::route

View file

@ -46,4 +46,58 @@ void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
<< data.retrans_time << '}';
}
// clang-format off
std::string familyToString(sa_family_t family) {
switch (family) {
case AF_UNSPEC: return "UNSPEC";
case AF_UNIX: return "UNIX";
case AF_INET: return "INET";
case AF_AX25: return "AX25";
case AF_IPX: return "IPX";
case AF_APPLETALK: return "APPLETALK";
case AF_NETROM: return "NETROM";
case AF_BRIDGE: return "BRIDGE";
case AF_ATMPVC: return "ATMPVC";
case AF_X25: return "X25";
case AF_INET6: return "INET6";
case AF_ROSE: return "ROSE";
case AF_DECnet: return "DECnet";
case AF_NETBEUI: return "NETBEUI";
case AF_SECURITY: return "SECURITY";
case AF_KEY: return "KEY";
case AF_NETLINK: return "NETLINK";
case AF_PACKET: return "PACKET";
case AF_ASH: return "ASH";
case AF_ECONET: return "ECONET";
case AF_ATMSVC: return "ATMSVC";
case AF_RDS: return "RDS";
case AF_SNA: return "SNA";
case AF_IRDA: return "IRDA";
case AF_PPPOX: return "PPPOX";
case AF_WANPIPE: return "WANPIPE";
case AF_LLC: return "LLC";
case 27 /*AF_IB*/: return "IB";
case 28 /*AF_MPLS*/: return "MPLS";
case AF_CAN: return "CAN";
case AF_TIPC: return "TIPC";
case AF_BLUETOOTH: return "BLUETOOTH";
case AF_IUCV: return "IUCV";
case AF_RXRPC: return "RXRPC";
case AF_ISDN: return "ISDN";
case AF_PHONET: return "PHONET";
case AF_IEEE802154: return "IEEE802154";
case AF_CAIF: return "CAIF";
case AF_ALG: return "ALG";
case AF_NFC: return "NFC";
case AF_VSOCK: return "VSOCK";
case AF_KCM: return "KCM";
case AF_QIPCRTR: return "QIPCRTR";
case 43 /*AF_SMC*/: return "SMC";
case 44 /*AF_XDP*/: return "XDP";
default:
return std::to_string(family);
}
}
// clang-format on
} // namespace android::nl::protocols::route

View file

@ -19,6 +19,7 @@
#include <libnl++/Buffer.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <sstream>
@ -30,6 +31,8 @@ void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
// ifla_cacheinfo
void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
std::string familyToString(sa_family_t family);
// rtnl_link_stats or rtnl_link_stats64
template <typename T>
void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {

View file

@ -22,8 +22,12 @@ namespace android::nl::protocols {
AttributeDefinition::ToStream flagsToStream(FlagsMap flags) {
return [flags](std::stringstream& ss, const Buffer<nlattr> attr) {
auto val = attr.data<uint64_t>().copyFirst();
auto value = attr.data<uint64_t>().copyFirst();
flagsToStream(ss, flags, value);
};
}
void flagsToStream(std::stringstream& ss, const FlagsMap& flags, uint64_t val) {
bool first = true;
for (const auto& [flag, name] : flags) {
if ((val & flag) != flag) continue;
@ -39,7 +43,6 @@ AttributeDefinition::ToStream flagsToStream(FlagsMap flags) {
if (!first) ss << '|';
ss << std::hex << val << std::dec;
};
}
void hwaddrToStream(std::stringstream& ss, const Buffer<nlattr> attr) {

View file

@ -34,6 +34,7 @@ void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
typedef std::map<uint64_t, std::string> FlagsMap;
AttributeDefinition::ToStream flagsToStream(FlagsMap flags);
void flagsToStream(std::stringstream& ss, const FlagsMap& flags, uint64_t value);
void hwaddrToStream(std::stringstream& ss, const Buffer<nlattr> attr);

View file

@ -70,6 +70,9 @@ static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
static bool configuratorStart(const std::string& filepath) {
base::SetDefaultTag("CanConfigurator");
LOG(WARNING) << "The HIDL version of CAN HAL has been deprecated, if this tool fails with "
<< "SIGABRT, you may need canhalconfigurator-aidl instead.";
auto pb_cfg = config::parseConfigFile(filepath);
if (!pb_cfg.has_value()) {
return false;

View file

@ -34,8 +34,8 @@ hidl_vec<hidl_string> getControlServices() {
auto manager = hidl::manager::V1_2::IServiceManager::getService();
hidl_vec<hidl_string> services;
manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?)"
<< std::endl;
CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?). "
<< "are you using the AIDL CanController?" << std::endl;
return services;
}

View file

@ -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.
//
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.automotive.can",
vendor_available: true,
srcs: ["android/hardware/automotive/can/*.aidl"],
stability: "vintf",
host_supported: true,
backend: {
java: {
enabled: false,
},
rust: {
enabled: true,
},
},
versions_with_info: [
{
version: "1",
imports: [],
},
],
frozen: true,
}

View file

@ -0,0 +1 @@
faa17409884ed5419fe73ebd24279109ca7549e1

View file

@ -0,0 +1,46 @@
/*
* 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.automotive.can;
@VintfStability
parcelable BusConfig {
String name;
android.hardware.automotive.can.BusConfig.InterfaceId interfaceId;
int bitrate;
union InterfaceId {
android.hardware.automotive.can.VirtualInterface virtualif;
android.hardware.automotive.can.NativeInterface nativeif;
android.hardware.automotive.can.SlcanInterface slcan;
android.hardware.automotive.can.IndexedInterface indexed;
}
}

View file

@ -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.automotive.can;
@VintfStability
interface ICanController {
android.hardware.automotive.can.InterfaceType[] getSupportedInterfaceTypes();
String getInterfaceName(in String busName);
String upBus(in android.hardware.automotive.can.BusConfig config);
void downBus(in String name);
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.can;
@VintfStability
parcelable IndexedInterface {
byte index;
}

View file

@ -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.automotive.can;
@Backing(type="byte") @VintfStability
enum InterfaceType {
VIRTUAL,
NATIVE,
SLCAN,
INDEXED,
}

View file

@ -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.automotive.can;
@VintfStability
parcelable NativeInterface {
android.hardware.automotive.can.NativeInterface.InterfaceId interfaceId;
union InterfaceId {
String ifname;
String[] serialno;
}
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.can;
@Backing(type="int") @VintfStability
enum Result {
OK,
UNKNOWN_ERROR,
INVALID_STATE,
NOT_SUPPORTED,
BAD_INTERFACE_ID,
BAD_BITRATE,
BAD_BUS_NAME,
INTERFACE_DOWN,
}

View file

@ -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.automotive.can;
@VintfStability
parcelable SlcanInterface {
android.hardware.automotive.can.SlcanInterface.InterfaceId interfaceId;
union InterfaceId {
String ttyname;
String[] serialno;
}
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.can;
@VintfStability
parcelable VirtualInterface {
String ifname;
}

View file

@ -0,0 +1,46 @@
/*
* 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.automotive.can;
@VintfStability
parcelable BusConfig {
String name;
android.hardware.automotive.can.BusConfig.InterfaceId interfaceId;
int bitrate;
union InterfaceId {
android.hardware.automotive.can.VirtualInterface virtualif;
android.hardware.automotive.can.NativeInterface nativeif;
android.hardware.automotive.can.SlcanInterface slcan;
android.hardware.automotive.can.IndexedInterface indexed;
}
}

View file

@ -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.automotive.can;
@VintfStability
interface ICanController {
android.hardware.automotive.can.InterfaceType[] getSupportedInterfaceTypes();
String getInterfaceName(in String busName);
String upBus(in android.hardware.automotive.can.BusConfig config);
void downBus(in String name);
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.can;
@VintfStability
parcelable IndexedInterface {
byte index;
}

View file

@ -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.automotive.can;
@Backing(type="byte") @VintfStability
enum InterfaceType {
VIRTUAL = 0,
NATIVE = 1,
SLCAN = 2,
INDEXED = 3,
}

View file

@ -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.automotive.can;
@VintfStability
parcelable NativeInterface {
android.hardware.automotive.can.NativeInterface.InterfaceId interfaceId;
union InterfaceId {
String ifname;
String[] serialno;
}
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.can;
@Backing(type="int") @VintfStability
enum Result {
OK = 0,
UNKNOWN_ERROR = 1,
INVALID_STATE = 2,
NOT_SUPPORTED = 3,
BAD_INTERFACE_ID = 4,
BAD_BITRATE = 5,
BAD_BUS_NAME = 6,
INTERFACE_DOWN = 7,
}

View file

@ -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.automotive.can;
@VintfStability
parcelable SlcanInterface {
android.hardware.automotive.can.SlcanInterface.InterfaceId interfaceId;
union InterfaceId {
String ttyname;
String[] serialno;
}
}

View file

@ -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.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.automotive.can;
@VintfStability
parcelable VirtualInterface {
String ifname;
}

View file

@ -0,0 +1,78 @@
/*
* 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.automotive.can;
import android.hardware.automotive.can.IndexedInterface;
import android.hardware.automotive.can.NativeInterface;
import android.hardware.automotive.can.SlcanInterface;
import android.hardware.automotive.can.VirtualInterface;
/**
* Configuration of the (physical or virtual) CAN bus.
*
* ISO TP and CAN FD support is dependent upon the hardware.
*/
@VintfStability
parcelable BusConfig {
/**
* Name by which a given bus may be referenced.
*
* It must consist of only alphanumeric characters and underscore
* (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
*
* This field is *not* meant to distinguish between hardware interfaces
* nor preselect parameters like bitrate.
*
* This field represents a more human-friendly name for a CAN bus:
* e.x. rather than /some/dev/can1234, "name" might be "BodyCAN" or "CCAN"
*/
String name;
/**
* Hardware interface configuration.
*
* This union's discriminator has an equivalent enum {@see InterfaceType} to
* express compatibility via getSupportedInterfaceTypes().
*/
union InterfaceId {
/** Virtual SocketCAN interface. */
VirtualInterface virtualif;
/** Native SocketCAN interface. */
NativeInterface nativeif;
/** Serial line CAN interface. */
SlcanInterface slcan;
/**
* Proprietary, device-specific interface.
*
* Non-SocketCAN interfaces should use this variant.
*/
IndexedInterface indexed;
}
InterfaceId interfaceId;
/**
* Bit rate for CAN communication.
*
* Typical bit rates are: 100000, 125000, 250000, 500000.
*
* For {@see interfaceId#virtual} interfaces, this value is ignored.
*/
int bitrate;
}

View file

@ -0,0 +1,64 @@
/*
* 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.automotive.can;
import android.hardware.automotive.can.BusConfig;
import android.hardware.automotive.can.InterfaceType;
import android.hardware.automotive.can.Result;
/**
* Represents a CAN controller that's capable of configuring CAN bus interfaces.
*
* The goal of this service is to configure and manage CAN interfaces.
*
* Providing an ICanController interface to configure CAN buses is optional.
* A system can elect to configure CAN buses manually if the hardware is
* dedicated to a specific application.
*/
@VintfStability
interface ICanController {
/**
* Fetches the list of interface types supported by this HAL server.
*
* @return iftypes The list of supported interface types.
*/
InterfaceType[] getSupportedInterfaceTypes();
/**
* Gets the interface name given the name of the bus. This will
*
* @param busName Name of the CAN bus who's interface name we would like
* (e.x. BCAN, CCAN, HS3, BodyCAN, ...)
* @return name of the socketcan network interface corresponding to busName
* (e.x. can0, vcan5, ...)
*/
String getInterfaceName(in String busName);
/**
* Bring up a CAN bus.
*
* @param config Configuration for the CAN bus.
* @return name of iface if successful
*/
String upBus(in BusConfig config);
/**
* Bring down a CAN bus.
*
* @param name Name of the bus (@see BusConfig#name} to bring down.
*/
void downBus(in String name);
}

View file

@ -0,0 +1,22 @@
/*
* 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.automotive.can;
@VintfStability
parcelable IndexedInterface {
/** Interface number, 0-based. */
byte index;
}

View file

@ -0,0 +1,37 @@
/*
* 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.automotive.can;
/**
* Type of an interface, an equivalent to BusConfig::InterfaceId
* union discriminator. Defines a number of specific standard hardware
* families and a generic catch-all type of {@see INDEXED}.
*/
@VintfStability
@Backing(type="byte")
enum InterfaceType {
/** Virtual SocketCAN interface. */
VIRTUAL,
/** Native SocketCAN interface. */
NATIVE,
/** Serial line CAN interface. */
SLCAN,
/** Proprietary, device-specific interface. */
INDEXED,
}

View file

@ -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.
*/
package android.hardware.automotive.can;
@VintfStability
parcelable NativeInterface {
union InterfaceId {
/** Interface name, such as can0. */
String ifname;
/**
* Alternatively to providing {@see ifname}, one may provide a list of
* interface serial number suffixes. If there happens to be a device
* (like USB2CAN) with a matching serial number suffix, the HAL service
* will locate it.
*
* Client may utilize this in two ways: by matching against the
* entire serial number, or the last few characters (usually
* one). The former is better for small-scale test deployments
* (with just a handful of vehicles), the latter is good for
* larger scale (where a small suffix list may support large
* test fleet).
*/
String[] serialno;
}
InterfaceId interfaceId;
}

View file

@ -0,0 +1,60 @@
/*
* 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.automotive.can;
/**
* Possible error codes (or OK) for ICanController.
*/
@VintfStability
@Backing(type="int")
enum Result {
OK,
/**
* General error class, if others are not applicable.
*/
UNKNOWN_ERROR,
/**
* Up request was called out of order (i.e. trying to up the interface
* twice).
*/
INVALID_STATE,
/** Interface type is not supported. */
NOT_SUPPORTED,
/**
* Provided interface ID (index, name, device path) doesn't exist or there
* is no device with a given serial number.
*/
BAD_INTERFACE_ID,
/** Provided bit rate is not supported by the hardware. */
BAD_BITRATE,
/**
* Provided bus name ({@see BusConfig#name}) has invalid format or doesn't exist.
*/
BAD_BUS_NAME,
/**
* The interface for the bus you are trying to interact with is currently
* down. As opposed to INVALID_STATE, this serves to warn the caller
* _before_ they attempt an invalid operation.
*/
INTERFACE_DOWN,
}

View file

@ -0,0 +1,32 @@
/*
* 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.automotive.can;
@VintfStability
parcelable SlcanInterface {
union InterfaceId {
/** Path to a device, such as /dev/ttyUSB0. */
String ttyname;
/**
* List of interface serial number suffixes.
* {@see Socketcan::serialno}
*/
String[] serialno;
}
InterfaceId interfaceId;
}

View file

@ -0,0 +1,25 @@
/*
* 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.automotive.can;
@VintfStability
parcelable VirtualInterface {
/**
* Interface name, such as vcan0. If the interface doesn't
* exist, HAL server must create it.
*/
String ifname;
}

View file

@ -0,0 +1,51 @@
//
// 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_binary {
name: "android.hardware.automotive.can-service",
init_rc: ["android.hardware.automotive.can.rc"],
defaults: ["android.hardware.automotive.can@defaults"],
vendor: true,
relative_install_path: "hw",
srcs: [
"CanBus.cpp",
"CanBusSlcan.cpp",
"CanBusNative.cpp",
"CanBusVirtual.cpp",
"CanController.cpp",
"service.cpp",
],
shared_libs: [
"android.hardware.automotive.can-V1-ndk",
"libbase",
"libbinder_ndk",
],
static_libs: [
"android.hardware.automotive.can@libnetdevice",
"android.hardware.automotive@libc++fs",
"libnl++",
],
vintf_fragments: ["android.hardware.automotive.can.xml"],
}

View file

@ -0,0 +1,93 @@
/*
* 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.
*/
#include "CanBus.h"
#include <android-base/logging.h>
#include <libnetdevice/libnetdevice.h>
namespace aidl::android::hardware::automotive::can {
CanBus::CanBus(std::string_view ifname) : mIfname(ifname) {}
CanBus::~CanBus() {
std::lock_guard<std::mutex> lck(mIsUpGuard);
CHECK(!mIsUp) << "Interface is still up while being destroyed";
}
Result CanBus::preUp() {
return Result::OK;
}
bool CanBus::postDown() {
return true;
}
std::string CanBus::getIfaceName() {
return mIfname;
}
Result CanBus::up() {
std::lock_guard<std::mutex> lck(mIsUpGuard);
if (mIsUp) {
LOG(WARNING) << "Interface is already up";
return Result::INVALID_STATE;
}
const auto preResult = preUp();
if (preResult != Result::OK) return preResult;
const auto isUp = ::android::netdevice::isUp(mIfname);
if (!isUp.has_value()) {
// preUp() should prepare the interface (either create or make sure it's there)
LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
return Result::BAD_INTERFACE_ID;
}
if (!*isUp && !::android::netdevice::up(mIfname)) {
LOG(ERROR) << "Can't bring " << mIfname << " up";
return Result::UNKNOWN_ERROR;
}
mDownAfterUse = !*isUp;
mIsUp = true;
return Result::OK;
}
Result CanBus::down() {
std::lock_guard<std::mutex> lck(mIsUpGuard);
if (!mIsUp) {
LOG(WARNING) << "Interface is already down";
return Result::INVALID_STATE;
}
mIsUp = false;
Result success = Result::OK;
if (mDownAfterUse && !::android::netdevice::down(mIfname)) {
LOG(ERROR) << "Can't bring " << mIfname << " down";
// don't return yet, let's try to do best-effort cleanup
success = Result::UNKNOWN_ERROR;
}
if (!postDown()) success = Result::UNKNOWN_ERROR;
return success;
}
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,77 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/automotive/can/Result.h>
#include <android-base/macros.h>
#include <utils/Mutex.h>
#include <atomic>
#include <mutex>
namespace aidl::android::hardware::automotive::can {
class CanBus {
public:
/**
* Some interface types (such as SLCAN) don't get an interface name until after being
* initialized, hence ifname is optional.
*
* You MUST ensure mIfname is initialized prior to the completion of preUp().
*/
CanBus(std::string_view ifname = std::string_view{""});
virtual ~CanBus();
Result up();
Result down();
std::string getIfaceName();
protected:
/**
* Prepare the SocketCAN interface.
*
* After calling this method, mIfname network interface is available and ready to be brought up.
*
* \return true upon success and false upon failure
*/
virtual Result preUp();
/**
* Cleanup after bringing the interface down.
*
* This is a counterpart to preUp().
*
* \return true upon success and false upon failure
*/
virtual bool postDown();
/** Network interface name. */
std::string mIfname;
private:
/**
* Guard for up flag is required to be held for entire time when the interface is being used
* because we don't want the interface to be torn down while executing that operation.
*/
std::mutex mIsUpGuard;
bool mIsUp GUARDED_BY(mIsUpGuard) = false;
bool mDownAfterUse;
};
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,54 @@
/*
* 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.
*/
#include "CanBusNative.h"
#include <android-base/logging.h>
#include <libnetdevice/can.h>
#include <libnetdevice/libnetdevice.h>
namespace aidl::android::hardware::automotive::can {
using namespace ::android;
CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate)
: CanBus(ifname), mBitrate(bitrate) {}
Result CanBusNative::preUp() {
if (!netdevice::exists(mIfname)) {
LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
return Result::BAD_INTERFACE_ID;
}
if (mBitrate == 0) {
// interface is already up and we just want to register it
return Result::OK;
}
if (!netdevice::down(mIfname)) {
LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
return Result::UNKNOWN_ERROR;
}
if (!netdevice::can::setBitrate(mIfname, mBitrate)) {
LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname;
return Result::BAD_BITRATE;
}
return Result::OK;
}
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,33 @@
/*
* 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.
*/
#pragma once
#include "CanBus.h"
namespace aidl::android::hardware::automotive::can {
class CanBusNative : public CanBus {
public:
CanBusNative(const std::string& ifname, uint32_t bitrate);
protected:
virtual Result preUp() override;
private:
const uint32_t mBitrate;
};
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,174 @@
/*
* 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.
*/
#include "CanBusSlcan.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <libnetdevice/libnetdevice.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <net/if.h>
#include <termios.h>
#include <map>
namespace aidl::android::hardware::automotive::can {
using namespace std::string_view_literals;
using namespace ::android::base;
namespace slcanprotocol {
static constexpr std::string_view kOpenCommand = "O\r"sv;
static constexpr std::string_view kCloseCommand = "C\r"sv;
static constexpr int kSlcanDiscipline = N_SLCAN;
static constexpr int kDefaultDiscipline = N_TTY;
static const std::map<uint32_t, std::string_view> kBitrateCommands = {
{10000, "C\rS0\r"sv}, {20000, "C\rS1\r"sv}, {50000, "C\rS2\r"sv},
{100000, "C\rS3\r"sv}, {125000, "C\rS4\r"sv}, {250000, "C\rS5\r"sv},
{500000, "C\rS6\r"sv}, {800000, "C\rS7\r"sv}, {1000000, "C\rS8\r"sv}};
} // namespace slcanprotocol
/**
* Serial Line CAN constructor
* \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
* \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
*/
CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
: CanBus(), mTtyPath(uartName), kBitrate(bitrate) {}
/** helper function to update CanBusSlcan object's iface name */
Result CanBusSlcan::updateIfaceName(unique_fd& uartFd) {
struct ifreq ifrequest = {};
/*
* Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
* to this tty. This is important in the event we are trying to register a SLCAN based iface
* that has already been configured and brought up.
*/
if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
PLOG(ERROR) << "Failed to get the name of the created device";
return Result::UNKNOWN_ERROR;
}
// Update the CanBus object with name that was assigned to it
mIfname = ifrequest.ifr_name;
return Result::OK;
}
Result CanBusSlcan::preUp() {
// verify valid bitrate and translate to serial command format
std::optional<std::string_view> canBitrateCommand = std::nullopt;
if (kBitrate != 0) {
const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
return Result::BAD_BITRATE;
}
canBitrateCommand = lookupIt->second;
}
/* Attempt to open the uart in r/w without blocking or becoming the
* controlling terminal */
mFd = unique_fd(open(mTtyPath.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC));
if (!mFd.ok()) {
PLOG(ERROR) << "SLCAN Failed to open " << mTtyPath;
return Result::BAD_INTERFACE_ID;
}
// If the device is already up, update the iface name in our CanBusSlcan object
if (kBitrate == 0) {
return updateIfaceName(mFd);
}
// blank terminal settings and pull them from the device
struct termios terminalSettings = {};
if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
PLOG(ERROR) << "Failed to read attrs of" << mTtyPath;
return Result::UNKNOWN_ERROR;
}
// change settings to raw mode
cfmakeraw(&terminalSettings);
// disable software flow control
terminalSettings.c_iflag &= ~IXOFF;
// enable hardware flow control
terminalSettings.c_cflag |= CRTSCTS;
struct serial_struct serialSettings;
// get serial settings
if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
PLOG(ERROR) << "Failed to read serial settings from " << mTtyPath;
return Result::UNKNOWN_ERROR;
}
// set low latency mode
serialSettings.flags |= ASYNC_LOW_LATENCY;
// apply serial settings
if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
PLOG(ERROR) << "Failed to set low latency mode on " << mTtyPath;
return Result::UNKNOWN_ERROR;
}
/* TCSADRAIN applies settings after we finish writing the rest of our
* changes (as opposed to TCSANOW, which changes immediately) */
if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
PLOG(ERROR) << "Failed to apply terminal settings to " << mTtyPath;
return Result::UNKNOWN_ERROR;
}
// apply speed setting for CAN
if (!WriteStringToFd(*canBitrateCommand, mFd)) {
PLOG(ERROR) << "Failed to apply CAN bitrate";
return Result::UNKNOWN_ERROR;
}
// TODO(b/144775286): set open flag & support listen only
if (!WriteStringToFd(slcanprotocol::kOpenCommand, mFd)) {
PLOG(ERROR) << "Failed to set open flag";
return Result::UNKNOWN_ERROR;
}
// set line discipline to slcan
if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
PLOG(ERROR) << "Failed to set line discipline to slcan";
return Result::UNKNOWN_ERROR;
}
// Update the CanBus object with name that was assigned to it
return updateIfaceName(mFd);
}
bool CanBusSlcan::postDown() {
// reset the line discipline to TTY mode
if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
LOG(ERROR) << "Failed to reset line discipline!";
return false;
}
// issue the close command
if (!WriteStringToFd(slcanprotocol::kCloseCommand, mFd)) {
LOG(ERROR) << "Failed to close tty!";
return false;
}
// close our unique_fd
mFd.reset();
return true;
}
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,40 @@
/*
* 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.
*/
#pragma once
#include "CanBus.h"
#include <android-base/unique_fd.h>
namespace aidl::android::hardware::automotive::can {
class CanBusSlcan : public CanBus {
public:
CanBusSlcan(const std::string& uartName, uint32_t bitrate);
protected:
virtual Result preUp() override;
virtual bool postDown() override;
private:
Result updateIfaceName(::android::base::unique_fd& uartFd);
const std::string mTtyPath;
const uint32_t kBitrate;
::android::base::unique_fd mFd;
};
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,52 @@
/*
* 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.
*/
#include "CanBusVirtual.h"
#include <android-base/logging.h>
#include <libnetdevice/libnetdevice.h>
namespace aidl::android::hardware::automotive::can {
using namespace ::android;
CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
Result CanBusVirtual::preUp() {
if (netdevice::exists(mIfname)) return Result::OK;
LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
mWasCreated = true;
if (!netdevice::add(mIfname, "vcan")) {
LOG(ERROR) << "Can't create vcan interface " << mIfname;
return Result::UNKNOWN_ERROR;
}
return Result::OK;
}
bool CanBusVirtual::postDown() {
if (mWasCreated) {
mWasCreated = false;
if (!netdevice::del(mIfname)) {
LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
return false;
}
}
return true;
}
} // namespace aidl::android::hardware::automotive::can

View file

@ -0,0 +1,34 @@
/*
* 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.
*/
#pragma once
#include "CanBus.h"
namespace aidl::android::hardware::automotive::can {
class CanBusVirtual : public CanBus {
public:
CanBusVirtual(const std::string& ifname);
protected:
virtual Result preUp() override;
virtual bool postDown() override;
private:
bool mWasCreated = false;
};
} // namespace aidl::android::hardware::automotive::can

Some files were not shown because too many files have changed in this diff Show more