mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:23:37 +00:00
Merge Android 12
Bug: 202323961 Merged-In: I76b505672b7c78b03a9c79df6473212ea5c65072 Change-Id: I262cbcc8dcfb0cad2b8e2f393c95829afe6b3827
This commit is contained in:
@@ -286,8 +286,6 @@ interface IStreamOut extends IStream {
|
||||
* timestamp must correspond to N rather than N+M. The terms 'recent' and
|
||||
* 'small' are not defined. They reflect the quality of the implementation.
|
||||
*
|
||||
* Optional method
|
||||
*
|
||||
* @return retval operation completion status.
|
||||
* @return frames count of presented audio frames.
|
||||
* @return timeStamp associated clock time.
|
||||
|
||||
@@ -276,6 +276,7 @@ package android.audio.policy.configuration.V7_0 {
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
|
||||
enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
<xs:enumeration value="AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" />
|
||||
<xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" />
|
||||
<xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" />
|
||||
<xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
|
||||
<xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
|
||||
<xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
|
||||
<xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
|
||||
|
||||
@@ -59,6 +59,7 @@ cc_defaults {
|
||||
"libaudio_system_headers",
|
||||
"libhardware_headers",
|
||||
"libmedia_headers",
|
||||
"libmediautils_headers",
|
||||
],
|
||||
|
||||
export_header_lib_headers: [
|
||||
|
||||
@@ -412,9 +412,9 @@ Return<void> StreamIn::prepareForReading(uint32_t frameSize, uint32_t framesCoun
|
||||
}
|
||||
|
||||
// Create and launch the thread.
|
||||
sp<ReadThread> tempReadThread =
|
||||
new ReadThread(&mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
|
||||
tempStatusMQ.get(), tempElfGroup.get());
|
||||
auto tempReadThread =
|
||||
sp<ReadThread>::make(&mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
|
||||
tempStatusMQ.get(), tempElfGroup.get());
|
||||
if (!tempReadThread->init()) {
|
||||
ALOGW("failed to start reader thread: %s", strerror(-status));
|
||||
sendError(Result::INVALID_ARGUMENTS);
|
||||
|
||||
@@ -164,7 +164,7 @@ StreamOut::~StreamOut() {
|
||||
status_t status = EventFlag::deleteEventFlag(&mEfGroup);
|
||||
ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
|
||||
}
|
||||
mCallback.clear();
|
||||
mCallback = nullptr;
|
||||
#if MAJOR_VERSION <= 5
|
||||
mDevice->closeOutputStream(mStream);
|
||||
// Closing the output stream in the HAL waits for the callback to finish,
|
||||
@@ -398,9 +398,9 @@ Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCou
|
||||
}
|
||||
|
||||
// Create and launch the thread.
|
||||
sp<WriteThread> tempWriteThread =
|
||||
new WriteThread(&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
|
||||
tempStatusMQ.get(), tempElfGroup.get());
|
||||
auto tempWriteThread =
|
||||
sp<WriteThread>::make(&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
|
||||
tempStatusMQ.get(), tempElfGroup.get());
|
||||
if (!tempWriteThread->init()) {
|
||||
ALOGW("failed to start writer thread: %s", strerror(-status));
|
||||
sendError(Result::INVALID_ARGUMENTS);
|
||||
@@ -463,7 +463,7 @@ Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
|
||||
|
||||
Return<Result> StreamOut::clearCallback() {
|
||||
if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
|
||||
mCallback.clear();
|
||||
mCallback = nullptr;
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
@@ -478,7 +478,7 @@ int StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie)
|
||||
// It's correct to hold an sp<> to callback because the reference
|
||||
// in the StreamOut instance can be cleared in the meantime. There is
|
||||
// no difference on which thread to run IStreamOutCallback's destructor.
|
||||
sp<IStreamOutCallback> callback = self->mCallback;
|
||||
sp<IStreamOutCallback> callback = self->mCallback.load();
|
||||
if (callback.get() == nullptr) return 0;
|
||||
ALOGV("asyncCallback() event %d", event);
|
||||
Return<void> result;
|
||||
@@ -736,7 +736,7 @@ Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& ca
|
||||
// static
|
||||
int StreamOut::asyncEventCallback(stream_event_callback_type_t event, void* param, void* cookie) {
|
||||
StreamOut* self = reinterpret_cast<StreamOut*>(cookie);
|
||||
sp<IStreamOutEventCallback> eventCallback = self->mEventCallback;
|
||||
sp<IStreamOutEventCallback> eventCallback = self->mEventCallback.load();
|
||||
if (eventCallback.get() == nullptr) return 0;
|
||||
ALOGV("%s event %d", __func__, event);
|
||||
Return<void> result;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <fmq/MessageQueue.h>
|
||||
#include <hidl/MQDescriptor.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <mediautils/Synchronization.h>
|
||||
#include <utils/Thread.h>
|
||||
|
||||
namespace android {
|
||||
@@ -158,9 +159,9 @@ struct StreamOut : public IStreamOut {
|
||||
audio_stream_out_t* mStream;
|
||||
const sp<Stream> mStreamCommon;
|
||||
const sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
|
||||
sp<IStreamOutCallback> mCallback; // Callback for non-blocking write and drain
|
||||
mediautils::atomic_sp<IStreamOutCallback> mCallback; // for non-blocking write and drain
|
||||
#if MAJOR_VERSION >= 6
|
||||
sp<IStreamOutEventCallback> mEventCallback;
|
||||
mediautils::atomic_sp<IStreamOutEventCallback> mEventCallback;
|
||||
#endif
|
||||
std::unique_ptr<CommandMQ> mCommandMQ;
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
|
||||
@@ -66,13 +66,13 @@ status_t CoreUtils::microphoneInfoFromHal(
|
||||
CONVERT_CHECKED(
|
||||
deviceAddressFromHal(halMicInfo.device, halMicInfo.address, &micInfo->deviceAddress),
|
||||
result);
|
||||
size_t chCount;
|
||||
for (chCount = 0; chCount < AUDIO_CHANNEL_COUNT_MAX; ++chCount) {
|
||||
if (halMicInfo.channel_mapping[chCount] == AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
|
||||
int chCount;
|
||||
for (chCount = AUDIO_CHANNEL_COUNT_MAX - 1; chCount >= 0; --chCount) {
|
||||
if (halMicInfo.channel_mapping[chCount] != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
micInfo->channelMapping.resize(chCount);
|
||||
micInfo->channelMapping.resize(chCount + 1);
|
||||
for (size_t ch = 0; ch < micInfo->channelMapping.size(); ch++) {
|
||||
micInfo->channelMapping[ch] = AudioMicrophoneChannelMapping(halMicInfo.channel_mapping[ch]);
|
||||
}
|
||||
|
||||
@@ -332,18 +332,21 @@ TEST_P(AudioPrimaryHidlTest, setMode) {
|
||||
#endif
|
||||
|
||||
for (int mode : {-2, -1, maxMode + 1}) {
|
||||
ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
|
||||
EXPECT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
|
||||
<< "mode=" << mode;
|
||||
}
|
||||
// Test valid values
|
||||
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
|
||||
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
|
||||
ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
|
||||
}
|
||||
|
||||
// AudioMode::CALL_SCREEN as support is optional
|
||||
#if MAJOR_VERSION >= 6
|
||||
ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
|
||||
EXPECT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
|
||||
#endif
|
||||
// Test valid values
|
||||
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
|
||||
AudioMode::NORMAL}) {
|
||||
EXPECT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
|
||||
}
|
||||
// Make sure to leave the test in normal mode
|
||||
getDevice()->setMode(AudioMode::NORMAL);
|
||||
}
|
||||
|
||||
TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
|
||||
|
||||
@@ -28,11 +28,13 @@ cc_defaults {
|
||||
defaults: ["VtsHalTargetTestDefaults"],
|
||||
static_libs: [
|
||||
"android.hardware.audio.common.test.utility",
|
||||
"libxml2",
|
||||
"audioclient-types-aidl-cpp",
|
||||
"libaudioclient_aidl_conversion",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
"libfmq",
|
||||
"libxml2",
|
||||
],
|
||||
header_libs: [
|
||||
"android.hardware.audio.common.util@all-versions",
|
||||
|
||||
@@ -22,4 +22,5 @@ aidl_interface {
|
||||
},
|
||||
},
|
||||
},
|
||||
versions: ["1"],
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
729cca96cb4732246b6ed1b3d15e2cbe63413afd
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.authsecret;
|
||||
@VintfStability
|
||||
interface IAuthSecret {
|
||||
oneway void setPrimaryUserCredential(in byte[] secret);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
pirozzoj@google.com
|
||||
twasilczyk@google.com
|
||||
pfg@google.com
|
||||
krachuri@google.com
|
||||
gurunagarajan@google.com
|
||||
keunyoung@google.com
|
||||
felipeal@google.com
|
||||
|
||||
@@ -140,6 +140,7 @@ TEST_P(CarAudioControlHidlTest, ContextMapping) {
|
||||
EXPECT_EQ(bus, -1);
|
||||
}
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CarAudioControlHidlTest);
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, CarAudioControlHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
|
||||
|
||||
@@ -149,6 +149,7 @@ TEST_P(CarAudioControlHidlTest, FocusChangeExercise) {
|
||||
AudioFocusChange::GAIN_TRANSIENT | 0);
|
||||
};
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CarAudioControlHidlTest);
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, CarAudioControlHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
|
||||
|
||||
23
automotive/audiocontrol/aidl/Android.bp
Normal file
23
automotive/audiocontrol/aidl/Android.bp
Normal file
@@ -0,0 +1,23 @@
|
||||
// This is the expected build file, but it may not be right in all cases
|
||||
|
||||
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.audiocontrol",
|
||||
vendor_available: true,
|
||||
srcs: ["android/hardware/automotive/audiocontrol/*.aidl"],
|
||||
stability: "vintf",
|
||||
backend: {
|
||||
java: {
|
||||
sdk_version: "module_current",
|
||||
},
|
||||
},
|
||||
versions: ["1"],
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ba2a7caca61683385b3b100e4faab1b4139fc547
|
||||
@@ -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,
|
||||
LOSS_TRANSIENT = -2,
|
||||
LOSS_TRANSIENT_CAN_DUCK = -3,
|
||||
}
|
||||
@@ -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
|
||||
parcelable DuckingInfo {
|
||||
int zoneId;
|
||||
String[] deviceAddressesToDuck;
|
||||
String[] deviceAddressesToUnduck;
|
||||
String[] usagesHoldingFocus;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 {
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
|
||||
// edit this file. It looks like you are doing that because you have modified
|
||||
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
|
||||
// from an interface or a field from a parcelable and it broke the build. That
|
||||
// breakage is intended.
|
||||
//
|
||||
// You must not make a backward incompatible changes to the AIDL files 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,
|
||||
LOSS_TRANSIENT = -2,
|
||||
LOSS_TRANSIENT_CAN_DUCK = -3,
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
|
||||
// edit this file. It looks like you are doing that because you have modified
|
||||
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
|
||||
// from an interface or a field from a parcelable and it broke the build. That
|
||||
// breakage is intended.
|
||||
//
|
||||
// You must not make a backward incompatible changes to the AIDL files 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;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
|
||||
// edit this file. It looks like you are doing that because you have modified
|
||||
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
|
||||
// from an interface or a field from a parcelable and it broke the build. That
|
||||
// breakage is intended.
|
||||
//
|
||||
// You must not make a backward incompatible changes to the AIDL files 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 {
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
|
||||
// edit this file. It looks like you are doing that because you have modified
|
||||
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
|
||||
// from an interface or a field from a parcelable and it broke the build. That
|
||||
// breakage is intended.
|
||||
//
|
||||
// You must not make a backward incompatible changes to the AIDL files 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);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
|
||||
// edit this file. It looks like you are doing that because you have modified
|
||||
// an AIDL interface in a backward-incompatible way, e.g., deleting a function
|
||||
// from an interface or a field from a parcelable and it broke the build. That
|
||||
// breakage is intended.
|
||||
//
|
||||
// You must not make a backward incompatible changes to the AIDL files 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;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.hardware.automotive.audiocontrol;
|
||||
|
||||
/**
|
||||
* Changes in audio focus that can be experienced
|
||||
*/
|
||||
@VintfStability
|
||||
@Backing(type="int")
|
||||
enum AudioFocusChange {
|
||||
NONE = 0,
|
||||
GAIN = 1,
|
||||
GAIN_TRANSIENT = 2,
|
||||
GAIN_TRANSIENT_MAY_DUCK = 3,
|
||||
GAIN_TRANSIENT_EXCLUSIVE = 4,
|
||||
LOSS = -1 * GAIN,
|
||||
LOSS_TRANSIENT = -1 * GAIN_TRANSIENT,
|
||||
LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK,
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.hardware.automotive.audiocontrol;
|
||||
|
||||
/**
|
||||
* The current ducking information for a single audio zone.
|
||||
*
|
||||
* <p>This includes devices to duck, as well as unduck based on the contents of a previous
|
||||
* {@link DuckingInfo}. Additionally, the current usages holding focus in the specified zone are
|
||||
* included, which were used to determine which addresses to duck.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable DuckingInfo {
|
||||
/**
|
||||
* ID of the associated audio zone
|
||||
*/
|
||||
int zoneId;
|
||||
|
||||
/**
|
||||
* List of addresses for audio output devices that should be ducked.
|
||||
*
|
||||
* <p>The provided address strings are defined in audio_policy_configuration.xml.
|
||||
*/
|
||||
String[] deviceAddressesToDuck;
|
||||
|
||||
/**
|
||||
* List of addresses for audio output devices that were previously be ducked and should now be
|
||||
* unducked.
|
||||
*
|
||||
* <p>The provided address strings are defined in audio_policy_configuration.xml.
|
||||
*/
|
||||
String[] deviceAddressesToUnduck;
|
||||
|
||||
/**
|
||||
* List of usages currently holding focus for this audio zone.
|
||||
*
|
||||
* <p> See {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
|
||||
*/
|
||||
String[] usagesHoldingFocus;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.hardware.automotive.audiocontrol;
|
||||
|
||||
import android.hardware.automotive.audiocontrol.AudioFocusChange;
|
||||
import android.hardware.automotive.audiocontrol.DuckingInfo;
|
||||
import android.hardware.automotive.audiocontrol.MutingInfo;
|
||||
import android.hardware.automotive.audiocontrol.IFocusListener;
|
||||
|
||||
/**
|
||||
* Interacts with the car's audio subsystem to manage audio sources and volumes
|
||||
*/
|
||||
@VintfStability
|
||||
interface IAudioControl {
|
||||
/**
|
||||
* Notifies HAL of changes in audio focus status for focuses requested or abandoned by the HAL.
|
||||
*
|
||||
* This will be called in response to IFocusListener's requestAudioFocus and
|
||||
* abandonAudioFocus, as well as part of any change in focus being held by the HAL due focus
|
||||
* request from other activities or services.
|
||||
*
|
||||
* The HAL is not required to wait for an callback of AUDIOFOCUS_GAIN before playing audio, nor
|
||||
* is it required to stop playing audio in the event of a AUDIOFOCUS_LOSS callback is received.
|
||||
*
|
||||
* @param usage The audio usage associated with the focus change {@code AttributeUsage}. See
|
||||
* {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
|
||||
* @param zoneId The identifier for the audio zone that the HAL is playing the stream in
|
||||
* @param focusChange the AudioFocusChange that has occurred.
|
||||
*/
|
||||
oneway void onAudioFocusChange(in String usage, in int zoneId, in AudioFocusChange focusChange);
|
||||
|
||||
/**
|
||||
* Notifies HAL of changes in output devices that the HAL should apply ducking to.
|
||||
*
|
||||
* This will be called in response to changes in audio focus, and will include a
|
||||
* {@link DuckingInfo} object per audio zone that experienced a change in audo focus.
|
||||
*
|
||||
* @param duckingInfos an array of {@link DuckingInfo} objects for the audio zones where audio
|
||||
* focus has changed.
|
||||
*/
|
||||
oneway void onDevicesToDuckChange(in DuckingInfo[] duckingInfos);
|
||||
|
||||
/**
|
||||
* Notifies HAL of changes in output devices that the HAL should apply muting to.
|
||||
*
|
||||
* This will be called in response to changes in audio mute state for each volume group
|
||||
* and will include a {@link MutingInfo} object per audio zone that experienced a mute state
|
||||
* event.
|
||||
*
|
||||
* @param mutingInfos an array of {@link MutingInfo} objects for the audio zones where audio
|
||||
* mute state has changed.
|
||||
*/
|
||||
oneway void onDevicesToMuteChange(in MutingInfo[] mutingInfos);
|
||||
|
||||
/**
|
||||
* Registers focus listener to be used by HAL for requesting and abandoning audio focus.
|
||||
*
|
||||
* It is expected that there will only ever be a single focus listener registered. If the
|
||||
* observer dies, the HAL implementation must unregister observer automatically. If called when
|
||||
* a listener is already registered, the existing one should be unregistered and replaced with
|
||||
* the new listener.
|
||||
*
|
||||
* @param listener the listener interface.
|
||||
*/
|
||||
oneway void registerFocusListener(in IFocusListener listener);
|
||||
|
||||
/**
|
||||
* Control the right/left balance setting of the car speakers.
|
||||
*
|
||||
* This is intended to shift the speaker volume toward the right (+) or left (-) side of
|
||||
* the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left.
|
||||
*
|
||||
* A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
|
||||
* range.
|
||||
*/
|
||||
oneway void setBalanceTowardRight(in float value);
|
||||
|
||||
/**
|
||||
* Control the fore/aft fade setting of the car speakers.
|
||||
*
|
||||
* This is intended to shift the speaker volume toward the front (+) or back (-) of the car.
|
||||
* 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward.
|
||||
*
|
||||
* A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
|
||||
* range.
|
||||
*/
|
||||
oneway void setFadeTowardFront(in float value);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.hardware.automotive.audiocontrol;
|
||||
|
||||
import android.hardware.automotive.audiocontrol.AudioFocusChange;
|
||||
|
||||
/**
|
||||
* Callback interface for audio focus listener.
|
||||
*
|
||||
* For typical configuration, the listener the car audio service.
|
||||
*/
|
||||
@VintfStability
|
||||
interface IFocusListener {
|
||||
/**
|
||||
* Called whenever HAL is abandoning focus as it is finished playing audio of a given usage in a
|
||||
* specific zone.
|
||||
*
|
||||
* In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
|
||||
* interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
|
||||
* before stopping audio playback.
|
||||
*
|
||||
* @param usage The audio usage for which the HAL is abandoning focus {@code AttributeUsage}.
|
||||
* See {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
|
||||
* @param zoneId The identifier for the audio zone that the HAL abandoning focus
|
||||
*/
|
||||
oneway void abandonAudioFocus(in String usage, in int zoneId);
|
||||
|
||||
/**
|
||||
* Called whenever HAL is requesting focus as it is starting to play audio of a given usage in a
|
||||
* specified zone.
|
||||
*
|
||||
* In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
|
||||
* interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
|
||||
* before playing audio.
|
||||
*
|
||||
* @param usage The audio usage associated with the focus request {@code AttributeUsage}. See
|
||||
* {@code audioUsage} in audio_policy_configuration.xsd for the list of allowed values.
|
||||
* @param zoneId The identifier for the audio zone where the HAL is requesting focus
|
||||
* @param focusGain The AudioFocusChange associated with this request. Should be one of the
|
||||
* following: GAIN, GAIN_TRANSIENT, GAIN_TRANSIENT_MAY_DUCK, GAIN_TRANSIENT_EXCLUSIVE.
|
||||
*/
|
||||
oneway void requestAudioFocus(in String usage, in int zoneId, in AudioFocusChange focusGain);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.hardware.automotive.audiocontrol;
|
||||
|
||||
/**
|
||||
* The current muting information for a single audio zone.
|
||||
*
|
||||
* <p>This includes devices to mute, as well as mute based on the contents of a previous
|
||||
* {@link MutingInfo}.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable MutingInfo {
|
||||
/**
|
||||
* ID of the associated audio zone
|
||||
*/
|
||||
int zoneId;
|
||||
|
||||
/**
|
||||
* List of addresses for audio output devices that should be muted.
|
||||
*
|
||||
* <p>The provided address strings are defined in audio_policy_configuration.xml.
|
||||
*/
|
||||
String[] deviceAddressesToMute;
|
||||
|
||||
/**
|
||||
* List of addresses for audio output devices that were previously be muted and should now be
|
||||
* unmuted.
|
||||
*
|
||||
* <p>The provided address strings are defined in audio_policy_configuration.xml.
|
||||
*/
|
||||
String[] deviceAddressesToUnmute;
|
||||
}
|
||||
45
automotive/audiocontrol/aidl/default/Android.bp
Normal file
45
automotive/audiocontrol/aidl/default/Android.bp
Normal 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.
|
||||
|
||||
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.audiocontrol-service.example",
|
||||
relative_install_path: "hw",
|
||||
init_rc: ["audiocontrol-default.rc"],
|
||||
vintf_fragments: ["audiocontrol-default.xml"],
|
||||
vendor: true,
|
||||
shared_libs: [
|
||||
"android.hardware.audio.common@7.0-enums",
|
||||
"android.frameworks.automotive.powerpolicy-V1-ndk",
|
||||
"android.hardware.automotive.audiocontrol-V1-ndk",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
"libpowerpolicyclient",
|
||||
],
|
||||
srcs: [
|
||||
"AudioControl.cpp",
|
||||
"main.cpp",
|
||||
"PowerPolicyClient.cpp",
|
||||
],
|
||||
}
|
||||
269
automotive/audiocontrol/aidl/default/AudioControl.cpp
Normal file
269
automotive/audiocontrol/aidl/default/AudioControl.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "AudioControl"
|
||||
// #define LOG_NDEBUG 0
|
||||
|
||||
#include "AudioControl.h"
|
||||
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/DuckingInfo.h>
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/IFocusListener.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include <android_audio_policy_configuration_V7_0-enums.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace aidl::android::hardware::automotive::audiocontrol {
|
||||
|
||||
using ::android::base::EqualsIgnoreCase;
|
||||
using ::android::base::ParseInt;
|
||||
using ::std::shared_ptr;
|
||||
using ::std::string;
|
||||
|
||||
namespace xsd {
|
||||
using namespace ::android::audio::policy::configuration::V7_0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
const float kLowerBound = -1.0f;
|
||||
const float kUpperBound = 1.0f;
|
||||
bool checkCallerHasWritePermissions(int fd) {
|
||||
// Double check that's only called by root - it should be be blocked at debug() level,
|
||||
// but it doesn't hurt to make sure...
|
||||
if (AIBinder_getCallingUid() != AID_ROOT) {
|
||||
dprintf(fd, "Must be root\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isValidValue(float value) {
|
||||
return (value >= kLowerBound) && (value <= kUpperBound);
|
||||
}
|
||||
|
||||
bool safelyParseInt(string s, int* out) {
|
||||
if (!ParseInt(s, out)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ndk::ScopedAStatus AudioControl::registerFocusListener(
|
||||
const shared_ptr<IFocusListener>& in_listener) {
|
||||
LOG(DEBUG) << "registering focus listener";
|
||||
|
||||
if (in_listener) {
|
||||
std::atomic_store(&mFocusListener, in_listener);
|
||||
} else {
|
||||
LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus AudioControl::setBalanceTowardRight(float value) {
|
||||
if (isValidValue(value)) {
|
||||
// Just log in this default mock implementation
|
||||
LOG(INFO) << "Balance set to " << value;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus AudioControl::setFadeTowardFront(float value) {
|
||||
if (isValidValue(value)) {
|
||||
// Just log in this default mock implementation
|
||||
LOG(INFO) << "Fader set to " << value;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus AudioControl::onAudioFocusChange(const string& in_usage, int32_t in_zoneId,
|
||||
AudioFocusChange in_focusChange) {
|
||||
LOG(INFO) << "Focus changed: " << toString(in_focusChange).c_str() << " for usage "
|
||||
<< in_usage.c_str() << " in zone " << in_zoneId;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus AudioControl::onDevicesToDuckChange(
|
||||
const std::vector<DuckingInfo>& in_duckingInfos) {
|
||||
LOG(INFO) << "AudioControl::onDevicesToDuckChange";
|
||||
for (const DuckingInfo& duckingInfo : in_duckingInfos) {
|
||||
LOG(INFO) << "zone: " << duckingInfo.zoneId;
|
||||
LOG(INFO) << "Devices to duck:";
|
||||
for (const auto& addressToDuck : duckingInfo.deviceAddressesToDuck) {
|
||||
LOG(INFO) << addressToDuck;
|
||||
}
|
||||
LOG(INFO) << "Devices to unduck:";
|
||||
for (const auto& addressToUnduck : duckingInfo.deviceAddressesToUnduck) {
|
||||
LOG(INFO) << addressToUnduck;
|
||||
}
|
||||
LOG(INFO) << "Usages holding focus:";
|
||||
for (const auto& usage : duckingInfo.usagesHoldingFocus) {
|
||||
LOG(INFO) << usage;
|
||||
}
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus AudioControl::onDevicesToMuteChange(
|
||||
const std::vector<MutingInfo>& in_mutingInfos) {
|
||||
LOG(INFO) << "AudioControl::onDevicesToMuteChange";
|
||||
for (const MutingInfo& mutingInfo : in_mutingInfos) {
|
||||
LOG(INFO) << "zone: " << mutingInfo.zoneId;
|
||||
LOG(INFO) << "Devices to mute:";
|
||||
for (const auto& addressToMute : mutingInfo.deviceAddressesToMute) {
|
||||
LOG(INFO) << addressToMute;
|
||||
}
|
||||
LOG(INFO) << "Devices to unmute:";
|
||||
for (const auto& addressToUnmute : mutingInfo.deviceAddressesToUnmute) {
|
||||
LOG(INFO) << addressToUnmute;
|
||||
}
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) {
|
||||
if (numArgs == 0) {
|
||||
return dumpsys(fd);
|
||||
}
|
||||
|
||||
string option = string(args[0]);
|
||||
if (EqualsIgnoreCase(option, "--help")) {
|
||||
return cmdHelp(fd);
|
||||
} else if (EqualsIgnoreCase(option, "--request")) {
|
||||
return cmdRequestFocus(fd, args, numArgs);
|
||||
} else if (EqualsIgnoreCase(option, "--abandon")) {
|
||||
return cmdAbandonFocus(fd, args, numArgs);
|
||||
} else {
|
||||
dprintf(fd, "Invalid option: %s\n", option.c_str());
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
binder_status_t AudioControl::dumpsys(int fd) {
|
||||
if (mFocusListener == nullptr) {
|
||||
dprintf(fd, "No focus listener registered\n");
|
||||
} else {
|
||||
dprintf(fd, "Focus listener registered\n");
|
||||
}
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
binder_status_t AudioControl::cmdHelp(int fd) const {
|
||||
dprintf(fd, "Usage: \n\n");
|
||||
dprintf(fd, "[no args]: dumps focus listener status\n");
|
||||
dprintf(fd, "--help: shows this help\n");
|
||||
dprintf(fd,
|
||||
"--request <USAGE> <ZONE_ID> <FOCUS_GAIN>: requests audio focus for specified "
|
||||
"usage (string), audio zone ID (int), and focus gain type (int)\n");
|
||||
dprintf(fd,
|
||||
"--abandon <USAGE> <ZONE_ID>: abandons audio focus for specified usage (string) and "
|
||||
"audio zone ID (int)\n");
|
||||
dprintf(fd, "See audio_policy_configuration.xsd for valid AudioUsage values.\n");
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
binder_status_t AudioControl::cmdRequestFocus(int fd, const char** args, uint32_t numArgs) {
|
||||
if (!checkCallerHasWritePermissions(fd)) {
|
||||
return STATUS_PERMISSION_DENIED;
|
||||
}
|
||||
if (numArgs != 4) {
|
||||
dprintf(fd,
|
||||
"Invalid number of arguments: please provide --request <USAGE> <ZONE_ID> "
|
||||
"<FOCUS_GAIN>\n");
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
string usage = string(args[1]);
|
||||
if (xsd::isUnknownAudioUsage(usage)) {
|
||||
dprintf(fd,
|
||||
"Unknown usage provided: %s. Please see audio_policy_configuration.xsd V7_0 "
|
||||
"for supported values\n",
|
||||
usage.c_str());
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
int zoneId;
|
||||
if (!safelyParseInt(string(args[2]), &zoneId)) {
|
||||
dprintf(fd, "Non-integer zoneId provided with request: %s\n", string(args[2]).c_str());
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
int focusGainValue;
|
||||
if (!safelyParseInt(string(args[3]), &focusGainValue)) {
|
||||
dprintf(fd, "Non-integer focusGain provided with request: %s\n", string(args[3]).c_str());
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
AudioFocusChange focusGain = AudioFocusChange(focusGainValue);
|
||||
|
||||
if (mFocusListener == nullptr) {
|
||||
dprintf(fd, "Unable to request focus - no focus listener registered\n");
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
mFocusListener->requestAudioFocus(usage, zoneId, focusGain);
|
||||
dprintf(fd, "Requested focus for usage %s, zoneId %d, and focusGain %d\n", usage.c_str(),
|
||||
zoneId, focusGain);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
binder_status_t AudioControl::cmdAbandonFocus(int fd, const char** args, uint32_t numArgs) {
|
||||
if (!checkCallerHasWritePermissions(fd)) {
|
||||
return STATUS_PERMISSION_DENIED;
|
||||
}
|
||||
if (numArgs != 3) {
|
||||
dprintf(fd, "Invalid number of arguments: please provide --abandon <USAGE> <ZONE_ID>\n");
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
string usage = string(args[1]);
|
||||
if (xsd::isUnknownAudioUsage(usage)) {
|
||||
dprintf(fd,
|
||||
"Unknown usage provided: %s. Please see audio_policy_configuration.xsd V7_0 "
|
||||
"for supported values\n",
|
||||
usage.c_str());
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
int zoneId;
|
||||
if (!safelyParseInt(string(args[2]), &zoneId)) {
|
||||
dprintf(fd, "Non-integer zoneId provided with abandon: %s\n", string(args[2]).c_str());
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
if (mFocusListener == nullptr) {
|
||||
dprintf(fd, "Unable to abandon focus - no focus listener registered\n");
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
mFocusListener->abandonAudioFocus(usage, zoneId);
|
||||
dprintf(fd, "Abandoned focus for usage %s and zoneId %d\n", usage.c_str(), zoneId);
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::automotive::audiocontrol
|
||||
55
automotive/audiocontrol/aidl/default/AudioControl.h
Normal file
55
automotive/audiocontrol/aidl/default/AudioControl.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H
|
||||
#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H
|
||||
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/BnAudioControl.h>
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/DuckingInfo.h>
|
||||
#include <aidl/android/hardware/automotive/audiocontrol/MutingInfo.h>
|
||||
|
||||
namespace aidl::android::hardware::automotive::audiocontrol {
|
||||
|
||||
class AudioControl : public BnAudioControl {
|
||||
public:
|
||||
ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId,
|
||||
AudioFocusChange in_focusChange) override;
|
||||
ndk::ScopedAStatus onDevicesToDuckChange(
|
||||
const std::vector<DuckingInfo>& in_duckingInfos) override;
|
||||
ndk::ScopedAStatus onDevicesToMuteChange(
|
||||
const std::vector<MutingInfo>& in_mutingInfos) override;
|
||||
ndk::ScopedAStatus registerFocusListener(
|
||||
const std::shared_ptr<IFocusListener>& in_listener) override;
|
||||
ndk::ScopedAStatus setBalanceTowardRight(float in_value) override;
|
||||
ndk::ScopedAStatus setFadeTowardFront(float in_value) override;
|
||||
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
|
||||
|
||||
private:
|
||||
// This focus listener will only be used by this HAL instance to communicate with
|
||||
// a single instance of CarAudioService. As such, it doesn't have explicit serialization.
|
||||
// If a different AudioControl implementation were to have multiple threads leveraging this
|
||||
// listener, then it should also include mutexes or make the listener atomic.
|
||||
std::shared_ptr<IFocusListener> mFocusListener;
|
||||
|
||||
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 dumpsys(int fd);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::automotive::audiocontrol
|
||||
|
||||
#endif // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H
|
||||
69
automotive/audiocontrol/aidl/default/PowerPolicyClient.cpp
Normal file
69
automotive/audiocontrol/aidl/default/PowerPolicyClient.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "PowerPolicyClient.h"
|
||||
#include "AudioControl.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace automotive {
|
||||
namespace audiocontrol {
|
||||
|
||||
namespace aafap = aidl::android::frameworks::automotive::powerpolicy;
|
||||
|
||||
using aafap::CarPowerPolicy;
|
||||
using aafap::CarPowerPolicyFilter;
|
||||
using aafap::PowerComponent;
|
||||
using ::android::frameworks::automotive::powerpolicy::hasComponent;
|
||||
using ::ndk::ScopedAStatus;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr PowerComponent kAudioComponent = PowerComponent::AUDIO;
|
||||
|
||||
} // namespace
|
||||
|
||||
PowerPolicyClient::PowerPolicyClient(std::shared_ptr<AudioControl> audioControl)
|
||||
: mAudioControl(audioControl) {}
|
||||
|
||||
void PowerPolicyClient::onInitFailed() {
|
||||
LOG(ERROR) << "Initializing power policy client failed";
|
||||
}
|
||||
|
||||
std::vector<PowerComponent> PowerPolicyClient::getComponentsOfInterest() {
|
||||
std::vector<PowerComponent> components{kAudioComponent};
|
||||
return components;
|
||||
}
|
||||
|
||||
ScopedAStatus PowerPolicyClient::onPolicyChanged(const CarPowerPolicy& powerPolicy) {
|
||||
if (hasComponent(powerPolicy.enabledComponents, kAudioComponent)) {
|
||||
LOG(DEBUG) << "Power policy: Audio component is enabled";
|
||||
// TODO(b/173719953): Do something when AUDIO is enabled.
|
||||
} else if (hasComponent(powerPolicy.disabledComponents, kAudioComponent)) {
|
||||
LOG(DEBUG) << "Power policy: Audio component is disabled";
|
||||
// TODO(b/173719953): Do something when AUDIO is disabled.
|
||||
}
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace audiocontrol
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
45
automotive/audiocontrol/aidl/default/PowerPolicyClient.h
Normal file
45
automotive/audiocontrol/aidl/default/PowerPolicyClient.h
Normal 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.
|
||||
*/
|
||||
|
||||
#ifndef AUTOMOTIVE_AUDIOCONTROL_AIDL_DEFAULT_POWERPOLICYCLIENT_H_
|
||||
#define AUTOMOTIVE_AUDIOCONTROL_AIDL_DEFAULT_POWERPOLICYCLIENT_H_
|
||||
|
||||
#include "PowerPolicyClientBase.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace aidl::android::hardware::automotive::audiocontrol {
|
||||
|
||||
class AudioControl;
|
||||
|
||||
class PowerPolicyClient
|
||||
: public ::android::frameworks::automotive::powerpolicy::PowerPolicyClientBase {
|
||||
public:
|
||||
explicit PowerPolicyClient(std::shared_ptr<AudioControl> audioControl);
|
||||
|
||||
void onInitFailed();
|
||||
std::vector<::aidl::android::frameworks::automotive::powerpolicy::PowerComponent>
|
||||
getComponentsOfInterest() override;
|
||||
::ndk::ScopedAStatus onPolicyChanged(
|
||||
const ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicy&) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AudioControl> mAudioControl;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::automotive::audiocontrol
|
||||
|
||||
#endif // AUTOMOTIVE_AUDIOCONTROL_AIDL_DEFAULT_POWERPOLICYCLIENT_H_
|
||||
@@ -0,0 +1,4 @@
|
||||
service vendor.audiocontrol-default /vendor/bin/hw/android.hardware.automotive.audiocontrol-service.example
|
||||
class hal
|
||||
user audioserver
|
||||
group system
|
||||
@@ -0,0 +1,6 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.automotive.audiocontrol</name>
|
||||
<fqname>IAudioControl/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
42
automotive/audiocontrol/aidl/default/main.cpp
Normal file
42
automotive/audiocontrol/aidl/default/main.cpp
Normal 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.
|
||||
*/
|
||||
|
||||
#include "AudioControl.h"
|
||||
#include "PowerPolicyClient.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
using aidl::android::hardware::automotive::audiocontrol::AudioControl;
|
||||
using aidl::android::hardware::automotive::audiocontrol::PowerPolicyClient;
|
||||
|
||||
int main() {
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
std::shared_ptr<AudioControl> audioControl = ::ndk::SharedRefBase::make<AudioControl>();
|
||||
|
||||
const std::string instance = std::string() + AudioControl::descriptor + "/default";
|
||||
binder_status_t status =
|
||||
AServiceManager_addService(audioControl->asBinder().get(), instance.c_str());
|
||||
CHECK(status == STATUS_OK);
|
||||
|
||||
std::shared_ptr<PowerPolicyClient> powerPolicyClient =
|
||||
::ndk::SharedRefBase::make<PowerPolicyClient>(audioControl);
|
||||
powerPolicyClient->init();
|
||||
|
||||
ABinderProcess_joinThreadPool();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
||||
47
automotive/audiocontrol/aidl/vts/Android.bp
Normal file
47
automotive/audiocontrol/aidl/vts/Android.bp
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "hardware_interfaces_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["hardware_interfaces_license"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "VtsAidlHalAudioControlTest",
|
||||
defaults: [
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
],
|
||||
generated_headers: ["audio_policy_configuration_V7_0"],
|
||||
generated_sources: ["audio_policy_configuration_V7_0"],
|
||||
header_libs: ["libxsdc-utils"],
|
||||
srcs: ["VtsHalAudioControlTargetTest.cpp"],
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
"libbase",
|
||||
"libxml2",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.automotive.audiocontrol-V1-cpp",
|
||||
"libgmock",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#define LOG_TAG "VtsAidlHalAudioControlTest"
|
||||
|
||||
#include <aidl/Gtest.h>
|
||||
#include <aidl/Vintf.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <android/hardware/automotive/audiocontrol/BnFocusListener.h>
|
||||
#include <android/hardware/automotive/audiocontrol/IAudioControl.h>
|
||||
#include <android/log.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/ProcessState.h>
|
||||
|
||||
using android::ProcessState;
|
||||
using android::sp;
|
||||
using android::String16;
|
||||
using android::binder::Status;
|
||||
using android::hardware::automotive::audiocontrol::AudioFocusChange;
|
||||
using android::hardware::automotive::audiocontrol::BnFocusListener;
|
||||
using android::hardware::automotive::audiocontrol::DuckingInfo;
|
||||
using android::hardware::automotive::audiocontrol::IAudioControl;
|
||||
using android::hardware::automotive::audiocontrol::MutingInfo;
|
||||
|
||||
#include "android_audio_policy_configuration_V7_0.h"
|
||||
|
||||
namespace xsd {
|
||||
using namespace android::audio::policy::configuration::V7_0;
|
||||
}
|
||||
|
||||
class AudioControlAidl : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
audioControl = android::waitForDeclaredService<IAudioControl>(String16(GetParam().c_str()));
|
||||
ASSERT_NE(audioControl, nullptr);
|
||||
}
|
||||
|
||||
sp<IAudioControl> audioControl;
|
||||
int32_t capabilities;
|
||||
};
|
||||
|
||||
TEST_P(AudioControlAidl, OnSetFadeTowardsFront) {
|
||||
ALOGI("Fader exercise test (silent)");
|
||||
|
||||
// Set the fader all the way to the back
|
||||
ASSERT_TRUE(audioControl->setFadeTowardFront(-1.0f).isOk());
|
||||
|
||||
// Set the fader all the way to the front
|
||||
ASSERT_TRUE(audioControl->setFadeTowardFront(1.0f).isOk());
|
||||
|
||||
// Set the fader part way toward the back
|
||||
ASSERT_TRUE(audioControl->setFadeTowardFront(-0.333f).isOk());
|
||||
|
||||
// Set the fader to a out of bounds value (driver should clamp)
|
||||
ASSERT_TRUE(audioControl->setFadeTowardFront(99999.9f).isOk());
|
||||
|
||||
// Set the fader to a negative out of bounds value (driver should clamp)
|
||||
ASSERT_TRUE(audioControl->setFadeTowardFront(-99999.9f).isOk());
|
||||
|
||||
// Set the fader back to the middle
|
||||
ASSERT_TRUE(audioControl->setFadeTowardFront(0.0f).isOk());
|
||||
}
|
||||
|
||||
TEST_P(AudioControlAidl, OnSetBalanceTowardsRight) {
|
||||
ALOGI("Balance exercise test (silent)");
|
||||
|
||||
// Set the balance all the way to the left
|
||||
ASSERT_TRUE(audioControl->setBalanceTowardRight(-1.0f).isOk());
|
||||
|
||||
// Set the balance all the way to the right
|
||||
ASSERT_TRUE(audioControl->setBalanceTowardRight(1.0f).isOk());
|
||||
|
||||
// Set the balance part way toward the left
|
||||
ASSERT_TRUE(audioControl->setBalanceTowardRight(-0.333f).isOk());
|
||||
|
||||
// Set the balance to a out of bounds value (driver should clamp)
|
||||
ASSERT_TRUE(audioControl->setBalanceTowardRight(99999.9f).isOk());
|
||||
|
||||
// Set the balance to a negative out of bounds value (driver should clamp)
|
||||
ASSERT_TRUE(audioControl->setBalanceTowardRight(-99999.9f).isOk());
|
||||
|
||||
// Set the balance back to the middle
|
||||
ASSERT_TRUE(audioControl->setBalanceTowardRight(0.0f).isOk());
|
||||
|
||||
// Set the balance back to the middle
|
||||
audioControl->setBalanceTowardRight(0.0f).isOk();
|
||||
}
|
||||
|
||||
struct FocusListenerMock : BnFocusListener {
|
||||
MOCK_METHOD(Status, requestAudioFocus,
|
||||
(const String16& usage, int32_t zoneId, AudioFocusChange focusGain));
|
||||
MOCK_METHOD(Status, abandonAudioFocus, (const String16& usage, int32_t zoneId));
|
||||
};
|
||||
|
||||
/*
|
||||
* Test focus listener registration.
|
||||
*
|
||||
* Verifies that:
|
||||
* - registerFocusListener succeeds;
|
||||
* - registering a second listener succeeds in replacing the first;
|
||||
* - closing handle does not crash;
|
||||
*/
|
||||
TEST_P(AudioControlAidl, FocusListenerRegistration) {
|
||||
ALOGI("Focus listener test");
|
||||
|
||||
sp<FocusListenerMock> listener = new FocusListenerMock();
|
||||
ASSERT_TRUE(audioControl->registerFocusListener(listener).isOk());
|
||||
|
||||
sp<FocusListenerMock> listener2 = new FocusListenerMock();
|
||||
ASSERT_TRUE(audioControl->registerFocusListener(listener2).isOk());
|
||||
};
|
||||
|
||||
TEST_P(AudioControlAidl, FocusChangeExercise) {
|
||||
ALOGI("Focus Change test");
|
||||
|
||||
String16 usage = String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA).c_str());
|
||||
ASSERT_TRUE(
|
||||
audioControl->onAudioFocusChange(usage, 0, AudioFocusChange::GAIN_TRANSIENT).isOk());
|
||||
};
|
||||
|
||||
TEST_P(AudioControlAidl, MuteChangeExercise) {
|
||||
ALOGI("Mute change test");
|
||||
|
||||
MutingInfo mutingInfo;
|
||||
mutingInfo.zoneId = 0;
|
||||
mutingInfo.deviceAddressesToMute = {String16("address 1"), String16("address 2")};
|
||||
mutingInfo.deviceAddressesToUnmute = {String16("address 3"), String16("address 4")};
|
||||
std::vector<MutingInfo> mutingInfos = {mutingInfo};
|
||||
ALOGI("Mute change test start");
|
||||
ASSERT_TRUE(audioControl->onDevicesToMuteChange(mutingInfos).isOk());
|
||||
}
|
||||
|
||||
TEST_P(AudioControlAidl, DuckChangeExercise) {
|
||||
ALOGI("Duck change test");
|
||||
|
||||
DuckingInfo duckingInfo;
|
||||
duckingInfo.zoneId = 0;
|
||||
duckingInfo.deviceAddressesToDuck = {String16("address 1"), String16("address 2")};
|
||||
duckingInfo.deviceAddressesToUnduck = {String16("address 3"), String16("address 4")};
|
||||
duckingInfo.usagesHoldingFocus = {
|
||||
String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA).c_str()),
|
||||
String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
|
||||
.c_str())};
|
||||
std::vector<DuckingInfo> duckingInfos = {duckingInfo};
|
||||
ALOGI("Duck change test start");
|
||||
ASSERT_TRUE(audioControl->onDevicesToDuckChange(duckingInfos).isOk());
|
||||
}
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl);
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Audiocontrol, AudioControlAidl,
|
||||
testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
|
||||
android::PrintInstanceNameToString);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ProcessState::self()->setThreadPoolMaxThreadCount(1);
|
||||
ProcessState::self()->startThreadPool();
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -62,5 +62,6 @@ cc_binary {
|
||||
static_libs: [
|
||||
"android.hardware.automotive.can@libnetdevice",
|
||||
"android.hardware.automotive@libc++fs",
|
||||
"libnl++",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, boo
|
||||
satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
|
||||
|
||||
if (rule.exclude) {
|
||||
// Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
|
||||
// Any exclude rule being satisfied invalidates the whole filter set.
|
||||
if (satisfied) return false;
|
||||
} else {
|
||||
anyNonExcludeRulePresent = true;
|
||||
|
||||
@@ -27,13 +27,16 @@ cc_library_static {
|
||||
name: "android.hardware.automotive.can@libnetdevice",
|
||||
defaults: ["android.hardware.automotive.can@defaults"],
|
||||
vendor_available: true,
|
||||
relative_install_path: "hw",
|
||||
srcs: [
|
||||
"NetlinkRequest.cpp",
|
||||
"NetlinkSocket.cpp",
|
||||
"can.cpp",
|
||||
"common.cpp",
|
||||
"ethtool.cpp",
|
||||
"ifreqs.cpp",
|
||||
"libnetdevice.cpp",
|
||||
"vlan.cpp",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
static_libs: [
|
||||
"libnl++",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 "NetlinkRequest.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace android::netdevice::impl {
|
||||
|
||||
static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
|
||||
return reinterpret_cast<struct rtattr*>( //
|
||||
reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
|
||||
}
|
||||
|
||||
struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
|
||||
size_t dataLen) {
|
||||
size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
|
||||
if (newLen > maxLen) {
|
||||
LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto attr = nlmsg_tail(n);
|
||||
attr->rta_len = RTA_SPACE(dataLen);
|
||||
attr->rta_type = type;
|
||||
if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
|
||||
|
||||
n->nlmsg_len = newLen;
|
||||
return attr;
|
||||
}
|
||||
|
||||
struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
|
||||
return addattr_l(n, maxLen, type, nullptr, 0);
|
||||
}
|
||||
|
||||
void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
|
||||
size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
|
||||
nest->rta_len = nestLen;
|
||||
}
|
||||
|
||||
} // namespace android::netdevice::impl
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <android-base/macros.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::netdevice {
|
||||
|
||||
typedef unsigned short rtattrtype_t; // as in rtnetlink.h
|
||||
typedef __u16 nlmsgtype_t; // as in netlink.h
|
||||
|
||||
/** Implementation details, do not use outside NetlinkRequest template. */
|
||||
namespace impl {
|
||||
|
||||
struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
|
||||
size_t dataLen);
|
||||
struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
|
||||
void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
|
||||
|
||||
} // namespace impl
|
||||
|
||||
/**
|
||||
* Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
|
||||
*
|
||||
* \param T specific message header (such as struct ifinfomsg)
|
||||
* \param BUFSIZE how much space to reserve for payload (not counting the header size)
|
||||
*/
|
||||
template <class T, unsigned int BUFSIZE = 128>
|
||||
struct NetlinkRequest {
|
||||
/**
|
||||
* Create empty message.
|
||||
*
|
||||
* \param type Message type (such as RTM_NEWLINK)
|
||||
* \param flags Message flags (such as NLM_F_REQUEST)
|
||||
*/
|
||||
NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
|
||||
mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
|
||||
mRequest.nlmsg.nlmsg_type = type;
|
||||
mRequest.nlmsg.nlmsg_flags = flags;
|
||||
}
|
||||
|
||||
/** \return pointer to raw netlink message header. */
|
||||
struct nlmsghdr* header() {
|
||||
return &mRequest.nlmsg;
|
||||
}
|
||||
/** Reference to message-specific header. */
|
||||
T& data() { return mRequest.data; }
|
||||
|
||||
/**
|
||||
* Adds an attribute of a simple type.
|
||||
*
|
||||
* If this method fails (i.e. due to insufficient space), the message will be marked
|
||||
* as bad (\see isGood).
|
||||
*
|
||||
* \param type attribute type (such as IFLA_IFNAME)
|
||||
* \param attr attribute data
|
||||
*/
|
||||
template <class A>
|
||||
void addattr(rtattrtype_t type, const A& attr) {
|
||||
if (!mIsGood) return;
|
||||
auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
|
||||
if (ap == nullptr) mIsGood = false;
|
||||
}
|
||||
|
||||
template <>
|
||||
void addattr(rtattrtype_t type, const std::string& s) {
|
||||
if (!mIsGood) return;
|
||||
auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
|
||||
if (ap == nullptr) mIsGood = false;
|
||||
}
|
||||
|
||||
/** Guard class to frame nested attributes. See nest(int). */
|
||||
struct Nest {
|
||||
Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
|
||||
~Nest() { mReq.nestEnd(mAttr); }
|
||||
|
||||
private:
|
||||
NetlinkRequest& mReq;
|
||||
struct rtattr* mAttr;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Nest);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add nested attribute.
|
||||
*
|
||||
* The returned object is a guard for auto-nesting children inside the argument attribute.
|
||||
* When the Nest object goes out of scope, the nesting attribute is closed.
|
||||
*
|
||||
* Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
|
||||
* inside IFLA_LINKINFO:
|
||||
* NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
|
||||
* {
|
||||
* auto linkinfo = req.nest(IFLA_LINKINFO);
|
||||
* req.addattr(IFLA_INFO_KIND, "can");
|
||||
* {
|
||||
* auto infodata = req.nest(IFLA_INFO_DATA);
|
||||
* req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
|
||||
* }
|
||||
* }
|
||||
* // use req
|
||||
*
|
||||
* \param type attribute type (such as IFLA_LINKINFO)
|
||||
*/
|
||||
Nest nest(int type) { return Nest(*this, type); }
|
||||
|
||||
/**
|
||||
* Indicates, whether the message is in a good state.
|
||||
*
|
||||
* The bad state is usually a result of payload buffer being too small.
|
||||
* You can modify BUFSIZE template parameter to fix this.
|
||||
*/
|
||||
bool isGood() const { return mIsGood; }
|
||||
|
||||
private:
|
||||
bool mIsGood = true;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlmsg;
|
||||
T data;
|
||||
char buf[BUFSIZE];
|
||||
} mRequest = {};
|
||||
|
||||
struct rtattr* nestStart(rtattrtype_t type) {
|
||||
if (!mIsGood) return nullptr;
|
||||
auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
|
||||
if (attr == nullptr) mIsGood = false;
|
||||
return attr;
|
||||
}
|
||||
|
||||
void nestEnd(struct rtattr* nest) {
|
||||
if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace android::netdevice
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 "NetlinkSocket.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace android::netdevice {
|
||||
|
||||
NetlinkSocket::NetlinkSocket(int protocol) {
|
||||
mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
|
||||
if (!mFd.ok()) {
|
||||
PLOG(ERROR) << "Can't open Netlink socket";
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_nl sa = {};
|
||||
sa.nl_family = AF_NETLINK;
|
||||
|
||||
if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
|
||||
PLOG(ERROR) << "Can't bind Netlink socket";
|
||||
mFd.reset();
|
||||
mFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
|
||||
if (mFailed) return false;
|
||||
|
||||
nlmsg->nlmsg_pid = 0; // kernel
|
||||
nlmsg->nlmsg_seq = mSeq++;
|
||||
nlmsg->nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
|
||||
|
||||
struct sockaddr_nl sa = {};
|
||||
sa.nl_family = AF_NETLINK;
|
||||
|
||||
struct msghdr msg = {};
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if (sendmsg(mFd.get(), &msg, 0) < 0) {
|
||||
PLOG(ERROR) << "Can't send Netlink message";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetlinkSocket::receiveAck() {
|
||||
if (mFailed) return false;
|
||||
|
||||
char buf[8192];
|
||||
|
||||
struct sockaddr_nl sa;
|
||||
struct iovec iov = {buf, sizeof(buf)};
|
||||
|
||||
struct msghdr msg = {};
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
const ssize_t status = recvmsg(mFd.get(), &msg, 0);
|
||||
if (status < 0) {
|
||||
PLOG(ERROR) << "Failed to receive Netlink message";
|
||||
return false;
|
||||
}
|
||||
size_t remainingLen = status;
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
LOG(ERROR) << "Failed to receive Netlink message: truncated";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
|
||||
nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
|
||||
// We're looking for error/ack message only, ignoring others.
|
||||
if (nlmsg->nlmsg_type != NLMSG_ERROR) {
|
||||
LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found error/ack message, return status.
|
||||
auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
|
||||
if (nlerr->error != 0) {
|
||||
LOG(ERROR) << "Received Netlink error message: " << nlerr->error;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Couldn't find any error/ack messages.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace android::netdevice
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 "NetlinkRequest.h"
|
||||
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
namespace android::netdevice {
|
||||
|
||||
/**
|
||||
* A wrapper around AF_NETLINK sockets.
|
||||
*
|
||||
* This class is not thread safe to use a single instance between multiple threads, but it's fine to
|
||||
* use multiple instances over multiple threads.
|
||||
*/
|
||||
struct NetlinkSocket {
|
||||
NetlinkSocket(int protocol);
|
||||
|
||||
/**
|
||||
* Send Netlink message to Kernel.
|
||||
*
|
||||
* \param msg Message to send, nlmsg_seq will be set to next sequence number
|
||||
* \return true, if succeeded
|
||||
*/
|
||||
template <class T, unsigned int BUFSIZE>
|
||||
bool send(NetlinkRequest<T, BUFSIZE>& req) {
|
||||
if (!req.isGood()) return false;
|
||||
return send(req.header());
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive Netlink ACK message from Kernel.
|
||||
*
|
||||
* \return true if received ACK message, false in case of error
|
||||
*/
|
||||
bool receiveAck();
|
||||
|
||||
private:
|
||||
uint32_t mSeq = 0;
|
||||
base::unique_fd mFd;
|
||||
bool mFailed = false;
|
||||
|
||||
bool send(struct nlmsghdr* msg);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
|
||||
};
|
||||
|
||||
} // namespace android::netdevice
|
||||
@@ -14,26 +14,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <libnetdevice/libnetdevice.h>
|
||||
#include <libnetdevice/can.h>
|
||||
|
||||
#include "NetlinkRequest.h"
|
||||
#include "NetlinkSocket.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <libnl++/MessageFactory.h>
|
||||
#include <libnl++/Socket.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
namespace android::netdevice::can {
|
||||
|
||||
static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
|
||||
|
||||
base::unique_fd socket(const std::string& ifname) {
|
||||
struct sockaddr_can addr = {};
|
||||
sockaddr_can addr = {};
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = nametoindex(ifname);
|
||||
if (addr.can_ifindex == 0) {
|
||||
@@ -57,7 +58,7 @@ base::unique_fd socket(const std::string& ifname) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
|
||||
if (0 != bind(sock.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
|
||||
LOG(ERROR) << "Can't bind to CAN interface " << ifname;
|
||||
return {};
|
||||
}
|
||||
@@ -66,31 +67,30 @@ base::unique_fd socket(const std::string& ifname) {
|
||||
}
|
||||
|
||||
bool setBitrate(std::string ifname, uint32_t bitrate) {
|
||||
struct can_bittiming bt = {};
|
||||
can_bittiming bt = {};
|
||||
bt.bitrate = bitrate;
|
||||
|
||||
NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
|
||||
nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
|
||||
|
||||
const auto ifidx = nametoindex(ifname);
|
||||
if (ifidx == 0) {
|
||||
req->ifi_index = nametoindex(ifname);
|
||||
if (req->ifi_index == 0) {
|
||||
LOG(ERROR) << "Can't find interface " << ifname;
|
||||
return false;
|
||||
}
|
||||
req.data().ifi_index = ifidx;
|
||||
|
||||
{
|
||||
auto linkinfo = req.nest(IFLA_LINKINFO);
|
||||
req.addattr(IFLA_INFO_KIND, "can");
|
||||
auto linkinfo = req.addNested(IFLA_LINKINFO);
|
||||
req.add(IFLA_INFO_KIND, "can");
|
||||
{
|
||||
auto infodata = req.nest(IFLA_INFO_DATA);
|
||||
auto infodata = req.addNested(IFLA_INFO_DATA);
|
||||
/* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
|
||||
* and IFLA_CAN_CTRLMODE as well. */
|
||||
req.addattr(IFLA_CAN_BITTIMING, bt);
|
||||
req.add(IFLA_CAN_BITTIMING, bt);
|
||||
}
|
||||
}
|
||||
|
||||
NetlinkSocket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck();
|
||||
nl::Socket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck(req);
|
||||
}
|
||||
|
||||
} // namespace android::netdevice::can
|
||||
|
||||
@@ -26,9 +26,8 @@ unsigned int nametoindex(const std::string& ifname) {
|
||||
const auto ifidx = if_nametoindex(ifname.c_str());
|
||||
if (ifidx != 0) return ifidx;
|
||||
|
||||
const auto err = errno;
|
||||
if (err != ENODEV) {
|
||||
LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err;
|
||||
if (errno != ENODEV) {
|
||||
PLOG(ERROR) << "if_nametoindex(" << ifname << ") failed";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::netdevice {
|
||||
|
||||
47
automotive/can/1.0/default/libnetdevice/ethtool.cpp
Normal file
47
automotive/can/1.0/default/libnetdevice/ethtool.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libnetdevice/ethtool.h>
|
||||
|
||||
#include "ifreqs.h"
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
namespace android::netdevice::ethtool {
|
||||
|
||||
std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command) {
|
||||
struct ethtool_value valueop = {};
|
||||
valueop.cmd = command;
|
||||
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
ifr.ifr_data = &valueop;
|
||||
|
||||
if (!ifreqs::send(SIOCETHTOOL, ifr)) return std::nullopt;
|
||||
return valueop.data;
|
||||
}
|
||||
|
||||
bool setValue(const std::string& ifname, uint32_t command, uint32_t value) {
|
||||
struct ethtool_value valueop = {};
|
||||
valueop.cmd = command;
|
||||
valueop.data = value;
|
||||
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
ifr.ifr_data = &valueop;
|
||||
|
||||
return ifreqs::send(SIOCETHTOOL, ifr);
|
||||
}
|
||||
|
||||
} // namespace android::netdevice::ethtool
|
||||
72
automotive/can/1.0/default/libnetdevice/ifreqs.cpp
Normal file
72
automotive/can/1.0/default/libnetdevice/ifreqs.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ifreqs.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace android::netdevice::ifreqs {
|
||||
|
||||
static constexpr int defaultSocketDomain = AF_INET;
|
||||
std::atomic_int socketDomain = defaultSocketDomain;
|
||||
|
||||
struct SocketParams {
|
||||
int domain;
|
||||
int type;
|
||||
int protocol;
|
||||
};
|
||||
|
||||
static const std::map<int, SocketParams> socketParams = {
|
||||
{AF_INET, {AF_INET, SOCK_DGRAM, 0}},
|
||||
{AF_CAN, {AF_CAN, SOCK_RAW, CAN_RAW}},
|
||||
};
|
||||
|
||||
static SocketParams getSocketParams(int domain) {
|
||||
if (socketParams.count(domain)) return socketParams.find(domain)->second;
|
||||
|
||||
auto params = socketParams.find(defaultSocketDomain)->second;
|
||||
params.domain = domain;
|
||||
return params;
|
||||
}
|
||||
|
||||
bool send(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()) {
|
||||
LOG(ERROR) << "Can't create socket";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(sock.get(), request, &ifr) < 0) {
|
||||
PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ifreq fromName(const std::string& ifname) {
|
||||
struct ifreq ifr = {};
|
||||
strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
|
||||
return ifr;
|
||||
}
|
||||
|
||||
} // namespace android::netdevice::ifreqs
|
||||
47
automotive/can/1.0/default/libnetdevice/ifreqs.h
Normal file
47
automotive/can/1.0/default/libnetdevice/ifreqs.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::netdevice::ifreqs {
|
||||
|
||||
/**
|
||||
* \see useSocketDomain()
|
||||
*/
|
||||
extern std::atomic_int socketDomain;
|
||||
|
||||
/**
|
||||
* Sends ioctl interface request.
|
||||
*
|
||||
* \param request Request type (such as SIOCGIFFLAGS)
|
||||
* \param ifr Request data (both input and output)
|
||||
* \return true if the call succeeded, false otherwise
|
||||
*/
|
||||
bool send(unsigned long request, struct ifreq& ifr);
|
||||
|
||||
/**
|
||||
* Initializes interface request with interface name.
|
||||
*
|
||||
* \param ifname Interface to initialize request with
|
||||
* \return Interface request with ifr_name field set to ifname
|
||||
*/
|
||||
struct ifreq fromName(const std::string& ifname);
|
||||
|
||||
} // namespace android::netdevice::ifreqs
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace android::netdevice::ethtool {
|
||||
|
||||
/**
|
||||
* Fetch a single value with ethtool_value.
|
||||
*
|
||||
* \see linux/ethtool.h
|
||||
* \param ifname Interface to fetch data for
|
||||
* \param command Fetch command (ETHTOOL_G*)
|
||||
* \return value, or nullopt if fetch failed
|
||||
*/
|
||||
std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command);
|
||||
|
||||
/**
|
||||
* Set a single value with ethtool_value.
|
||||
*
|
||||
* \see linux/ethtool.h
|
||||
* \param ifname Interface to set data for
|
||||
* \param command Set command (ETHTOOL_S*)
|
||||
* \param value New value
|
||||
* \return true if succeeded, false otherwise
|
||||
*/
|
||||
bool setValue(const std::string& ifname, uint32_t command, uint32_t value);
|
||||
|
||||
} // namespace android::netdevice::ethtool
|
||||
@@ -16,11 +16,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace android::netdevice {
|
||||
|
||||
typedef std::array<uint8_t, ETH_ALEN> hwaddr_t;
|
||||
|
||||
/**
|
||||
* Configures libnetdevice to use other socket domain than AF_INET,
|
||||
* what requires less permissive SEPolicy rules for a given process.
|
||||
*
|
||||
* In such case, the process would only be able to control interfaces of a given kind.
|
||||
|
||||
* \param domain Socket domain to use (e.g. AF_CAN), see socket(2) for details
|
||||
*/
|
||||
void useSocketDomain(int domain);
|
||||
|
||||
/**
|
||||
* Checks, if the network interface exists.
|
||||
*
|
||||
@@ -37,6 +53,36 @@ bool exists(std::string ifname);
|
||||
*/
|
||||
std::optional<bool> isUp(std::string ifname);
|
||||
|
||||
/**
|
||||
* Interface condition to wait for.
|
||||
*/
|
||||
enum class WaitCondition {
|
||||
/**
|
||||
* Interface is present (but not necessarily up).
|
||||
*/
|
||||
PRESENT,
|
||||
|
||||
/**
|
||||
* Interface is up.
|
||||
*/
|
||||
PRESENT_AND_UP,
|
||||
|
||||
/**
|
||||
* Interface is down or not present (disconnected) at all.
|
||||
*/
|
||||
DOWN_OR_GONE,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* interface should stop the wait.
|
||||
*/
|
||||
void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true);
|
||||
|
||||
/**
|
||||
* Brings network interface up.
|
||||
*
|
||||
@@ -70,4 +116,22 @@ bool add(std::string dev, std::string type);
|
||||
*/
|
||||
bool del(std::string dev);
|
||||
|
||||
/**
|
||||
* Fetches interface's hardware address.
|
||||
*
|
||||
* \param ifname Interface name
|
||||
* \return Hardware address (MAC address) or nullopt if the lookup failed
|
||||
*/
|
||||
std::optional<hwaddr_t> getHwAddr(const std::string& ifname);
|
||||
|
||||
/**
|
||||
* Changes interface's hardware address.
|
||||
*
|
||||
* \param ifname Interface name
|
||||
* \param hwaddr New hardware address to set
|
||||
*/
|
||||
bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr);
|
||||
|
||||
} // namespace android::netdevice
|
||||
|
||||
bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::netdevice::vlan {
|
||||
|
||||
bool add(const std::string& eth, const std::string& vlan, uint16_t id);
|
||||
|
||||
} // namespace android::netdevice::vlan
|
||||
@@ -16,83 +16,178 @@
|
||||
|
||||
#include <libnetdevice/libnetdevice.h>
|
||||
|
||||
#include "NetlinkRequest.h"
|
||||
#include "NetlinkSocket.h"
|
||||
#include "common.h"
|
||||
#include "ifreqs.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <libnl++/MessageFactory.h>
|
||||
#include <libnl++/Socket.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace android::netdevice {
|
||||
|
||||
void useSocketDomain(int domain) {
|
||||
ifreqs::socketDomain = domain;
|
||||
}
|
||||
|
||||
bool exists(std::string ifname) {
|
||||
return nametoindex(ifname) != 0;
|
||||
}
|
||||
|
||||
static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
|
||||
/* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0),
|
||||
* but SEPolicy forces us to limit our flexibility here. */
|
||||
base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW));
|
||||
if (!sock.ok()) {
|
||||
LOG(ERROR) << "Can't create socket";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(sock.get(), request, &ifr) < 0) {
|
||||
PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct ifreq ifreqFromName(const std::string& ifname) {
|
||||
struct ifreq ifr = {};
|
||||
strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
|
||||
return ifr;
|
||||
}
|
||||
|
||||
std::optional<bool> isUp(std::string ifname) {
|
||||
struct ifreq ifr = ifreqFromName(ifname);
|
||||
if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
|
||||
return ifr.ifr_flags & IFF_UP;
|
||||
}
|
||||
|
||||
bool up(std::string ifname) {
|
||||
struct ifreq ifr = ifreqFromName(ifname);
|
||||
if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
return sendIfreq(SIOCSIFFLAGS, ifr);
|
||||
return ifreqs::send(SIOCSIFFLAGS, ifr);
|
||||
}
|
||||
|
||||
bool down(std::string ifname) {
|
||||
struct ifreq ifr = ifreqFromName(ifname);
|
||||
if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
return sendIfreq(SIOCSIFFLAGS, ifr);
|
||||
return ifreqs::send(SIOCSIFFLAGS, ifr);
|
||||
}
|
||||
|
||||
bool add(std::string dev, std::string type) {
|
||||
NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
|
||||
req.addattr(IFLA_IFNAME, dev);
|
||||
nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
|
||||
NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
|
||||
req.add(IFLA_IFNAME, dev);
|
||||
|
||||
{
|
||||
auto linkinfo = req.nest(IFLA_LINKINFO);
|
||||
req.addattr(IFLA_INFO_KIND, type);
|
||||
auto linkinfo = req.addNested(IFLA_LINKINFO);
|
||||
req.add(IFLA_INFO_KIND, type);
|
||||
}
|
||||
|
||||
NetlinkSocket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck();
|
||||
nl::Socket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck(req);
|
||||
}
|
||||
|
||||
bool del(std::string dev) {
|
||||
NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
|
||||
req.addattr(IFLA_IFNAME, dev);
|
||||
nl::MessageFactory<ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
|
||||
req.add(IFLA_IFNAME, dev);
|
||||
|
||||
NetlinkSocket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck();
|
||||
nl::Socket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck(req);
|
||||
}
|
||||
|
||||
std::optional<hwaddr_t> getHwAddr(const std::string& ifname) {
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return std::nullopt;
|
||||
|
||||
hwaddr_t hwaddr;
|
||||
memcpy(hwaddr.data(), ifr.ifr_hwaddr.sa_data, hwaddr.size());
|
||||
return hwaddr;
|
||||
}
|
||||
|
||||
bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr) {
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
|
||||
// fetch sa_family
|
||||
if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return false;
|
||||
|
||||
memcpy(ifr.ifr_hwaddr.sa_data, hwaddr.data(), hwaddr.size());
|
||||
return ifreqs::send(SIOCSIFHWADDR, ifr);
|
||||
}
|
||||
|
||||
std::optional<bool> isUp(std::string ifname) {
|
||||
auto ifr = ifreqs::fromName(ifname);
|
||||
if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
|
||||
return ifr.ifr_flags & IFF_UP;
|
||||
}
|
||||
|
||||
struct WaitState {
|
||||
bool present;
|
||||
bool up;
|
||||
|
||||
bool satisfied(WaitCondition cnd) const {
|
||||
switch (cnd) {
|
||||
case WaitCondition::PRESENT:
|
||||
if (present) return true;
|
||||
break;
|
||||
case WaitCondition::PRESENT_AND_UP:
|
||||
if (present && up) return true;
|
||||
break;
|
||||
case WaitCondition::DOWN_OR_GONE:
|
||||
if (!present || !up) return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static std::string toString(WaitCondition cnd) {
|
||||
switch (cnd) {
|
||||
case WaitCondition::PRESENT:
|
||||
return "become present";
|
||||
case WaitCondition::PRESENT_AND_UP:
|
||||
return "come up";
|
||||
case WaitCondition::DOWN_OR_GONE:
|
||||
return "go down";
|
||||
}
|
||||
}
|
||||
|
||||
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, ","));
|
||||
auto str = ss.str();
|
||||
str.pop_back();
|
||||
return str;
|
||||
}
|
||||
|
||||
void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) {
|
||||
nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
|
||||
|
||||
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 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);
|
||||
}
|
||||
};
|
||||
|
||||
if (isFullySatisfied()) return;
|
||||
|
||||
LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << 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;
|
||||
|
||||
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};
|
||||
|
||||
if (isFullySatisfied()) {
|
||||
LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
|
||||
<< " to " << toString(cnd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG(FATAL) << "Can't read Netlink socket";
|
||||
}
|
||||
|
||||
} // namespace android::netdevice
|
||||
|
||||
bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) {
|
||||
static_assert(lhs.size() == ETH_ALEN);
|
||||
return 0 == memcmp(lhs.data(), rhs, lhs.size());
|
||||
}
|
||||
|
||||
55
automotive/can/1.0/default/libnetdevice/vlan.cpp
Normal file
55
automotive/can/1.0/default/libnetdevice/vlan.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libnetdevice/vlan.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <libnl++/MessageFactory.h>
|
||||
#include <libnl++/Socket.h>
|
||||
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
namespace android::netdevice::vlan {
|
||||
|
||||
bool add(const std::string& eth, const std::string& vlan, uint16_t id) {
|
||||
const auto ethidx = nametoindex(eth);
|
||||
if (ethidx == 0) {
|
||||
LOG(ERROR) << "Ethernet interface " << eth << " doesn't exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
|
||||
NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
|
||||
req.add(IFLA_IFNAME, vlan);
|
||||
req.add<uint32_t>(IFLA_LINK, ethidx);
|
||||
|
||||
{
|
||||
auto linkinfo = req.addNested(IFLA_LINKINFO);
|
||||
req.add(IFLA_INFO_KIND, "vlan");
|
||||
|
||||
{
|
||||
auto linkinfo = req.addNested(IFLA_INFO_DATA);
|
||||
req.add(IFLA_VLAN_ID, id);
|
||||
}
|
||||
}
|
||||
|
||||
nl::Socket sock(NETLINK_ROUTE);
|
||||
return sock.send(req) && sock.receiveAck(req);
|
||||
}
|
||||
|
||||
} // namespace android::netdevice::vlan
|
||||
53
automotive/can/1.0/default/libnl++/Android.bp
Normal file
53
automotive/can/1.0/default/libnl++/Android.bp
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright (C) 2019 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_library_static {
|
||||
name: "libnl++",
|
||||
defaults: ["android.hardware.automotive.can@defaults"],
|
||||
vendor_available: true,
|
||||
srcs: [
|
||||
"protocols/common/Empty.cpp",
|
||||
"protocols/common/Error.cpp",
|
||||
"protocols/generic/Ctrl.cpp",
|
||||
"protocols/generic/FamilyTracker.cpp",
|
||||
"protocols/generic/Generic.cpp",
|
||||
"protocols/generic/GenericMessageBase.cpp",
|
||||
"protocols/generic/Unknown.cpp",
|
||||
"protocols/generic/families/Nl80211.cpp",
|
||||
"protocols/route/Link.cpp",
|
||||
"protocols/route/Route.cpp",
|
||||
"protocols/route/structs.cpp",
|
||||
"protocols/MessageDefinition.cpp",
|
||||
"protocols/NetlinkProtocol.cpp",
|
||||
"protocols/all.cpp",
|
||||
"Attributes.cpp",
|
||||
"MessageFactory.cpp",
|
||||
"MessageMutator.cpp",
|
||||
"Socket.cpp",
|
||||
"common.cpp",
|
||||
"printer.cpp",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
84
automotive/can/1.0/default/libnl++/Attributes.cpp
Normal file
84
automotive/can/1.0/default/libnl++/Attributes.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libnl++/Attributes.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
Attributes::Attributes() {}
|
||||
|
||||
Attributes::Attributes(Buffer<nlattr> buffer) : Buffer<nlattr>(buffer) {}
|
||||
|
||||
const Attributes::Index& Attributes::index() const {
|
||||
if (mIndex.has_value()) return *mIndex;
|
||||
|
||||
mIndex = Index();
|
||||
auto& index = *mIndex;
|
||||
|
||||
for (auto attr : static_cast<Buffer<nlattr>>(*this)) {
|
||||
index.emplace(attr->nla_type, attr);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool Attributes::contains(nlattrtype_t attrtype) const {
|
||||
return index().count(attrtype) > 0;
|
||||
}
|
||||
|
||||
/* Parser specializations for selected types (more to come if necessary). */
|
||||
|
||||
template <>
|
||||
Attributes Attributes::parse(Buffer<nlattr> buf) {
|
||||
return buf.data<nlattr>();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string Attributes::parse(Buffer<nlattr> buf) {
|
||||
const auto rawString = buf.data<char>().getRaw();
|
||||
std::string str(rawString.ptr(), rawString.len());
|
||||
|
||||
str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T parseUnsigned(Buffer<nlattr> buf) {
|
||||
return buf.data<T>().copyFirst();
|
||||
}
|
||||
|
||||
template <>
|
||||
uint8_t Attributes::parse(Buffer<nlattr> buf) {
|
||||
return parseUnsigned<uint8_t>(buf);
|
||||
}
|
||||
|
||||
template <>
|
||||
uint16_t Attributes::parse(Buffer<nlattr> buf) {
|
||||
return parseUnsigned<uint16_t>(buf);
|
||||
}
|
||||
|
||||
template <>
|
||||
uint32_t Attributes::parse(Buffer<nlattr> buf) {
|
||||
return parseUnsigned<uint32_t>(buf);
|
||||
}
|
||||
|
||||
template <>
|
||||
uint64_t Attributes::parse(Buffer<nlattr> buf) {
|
||||
return parseUnsigned<uint64_t>(buf);
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
52
automotive/can/1.0/default/libnl++/MessageFactory.cpp
Normal file
52
automotive/can/1.0/default/libnl++/MessageFactory.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <libnl++/MessageFactory.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <libnl++/bits.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
static nlattr* tail(nlmsghdr* msg) {
|
||||
return reinterpret_cast<nlattr*>(uintptr_t(msg) + impl::align(msg->nlmsg_len));
|
||||
}
|
||||
|
||||
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;
|
||||
if (newLen > maxLen) {
|
||||
LOG(ERROR) << "Can't add attribute of size " << dataLen //
|
||||
<< " - exceeded maxLen: " << newLen << " > " << maxLen;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto attr = tail(msg);
|
||||
attr->nla_len = totalAttrLen;
|
||||
attr->nla_type = type;
|
||||
if (dataLen > 0) memcpy(impl::data<nlattr, void>(attr), data, dataLen);
|
||||
|
||||
msg->nlmsg_len = newLen;
|
||||
return attr;
|
||||
}
|
||||
|
||||
void MessageFactoryBase::closeNested(nlmsghdr* msg, nlattr* nested) {
|
||||
if (nested == nullptr) return;
|
||||
nested->nla_len = uintptr_t(tail(msg)) - uintptr_t(nested);
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
50
automotive/can/1.0/default/libnl++/MessageMutator.cpp
Normal file
50
automotive/can/1.0/default/libnl++/MessageMutator.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libnl++/MessageMutator.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
MessageMutator::MessageMutator(nlmsghdr* buffer, size_t totalLen)
|
||||
: mConstBuffer(buffer, totalLen), mMutableBuffer(buffer) {
|
||||
CHECK(totalLen >= sizeof(nlmsghdr));
|
||||
}
|
||||
|
||||
nlmsghdr* MessageMutator::operator->() const {
|
||||
return mMutableBuffer;
|
||||
}
|
||||
|
||||
MessageMutator::operator Buffer<nlmsghdr>() const {
|
||||
return mConstBuffer;
|
||||
}
|
||||
|
||||
uint64_t MessageMutator::read(Buffer<nlattr> attr) const {
|
||||
return attr.data<uint64_t>().copyFirst();
|
||||
}
|
||||
|
||||
void MessageMutator::write(Buffer<nlattr> attr, uint64_t val) const {
|
||||
const auto attrData = attr.data<uint64_t>();
|
||||
const auto offset = mConstBuffer.getOffset(attrData);
|
||||
CHECK(offset.has_value()) << "Trying to write attribute that's not a member of this message";
|
||||
|
||||
const auto writeableBuffer = reinterpret_cast<uint8_t*>(mMutableBuffer) + *offset;
|
||||
const auto attrSize = attrData.getRaw().len();
|
||||
|
||||
if (attrSize > sizeof(val)) memset(writeableBuffer, 0, attrSize);
|
||||
memcpy(writeableBuffer, &val, std::min(sizeof(val), attrSize));
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
203
automotive/can/1.0/default/libnl++/Socket.cpp
Normal file
203
automotive/can/1.0/default/libnl++/Socket.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <libnl++/Socket.h>
|
||||
|
||||
#include <libnl++/printer.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* Print all outbound/inbound Netlink messages.
|
||||
*/
|
||||
static constexpr bool kSuperVerbose = false;
|
||||
|
||||
Socket::Socket(int protocol, unsigned pid, uint32_t groups) : mProtocol(protocol) {
|
||||
mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
|
||||
if (!mFd.ok()) {
|
||||
PLOG(ERROR) << "Can't open Netlink socket";
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
sockaddr_nl sa = {};
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_pid = pid;
|
||||
sa.nl_groups = groups;
|
||||
|
||||
if (bind(mFd.get(), reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) < 0) {
|
||||
PLOG(ERROR) << "Can't bind Netlink socket";
|
||||
mFd.reset();
|
||||
mFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
|
||||
if constexpr (kSuperVerbose) {
|
||||
LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
|
||||
<< toString(msg, mProtocol);
|
||||
}
|
||||
if (mFailed) return false;
|
||||
|
||||
mSeq = msg->nlmsg_seq;
|
||||
const auto rawMsg = msg.getRaw();
|
||||
const auto bytesSent = sendto(mFd.get(), rawMsg.ptr(), rawMsg.len(), 0,
|
||||
reinterpret_cast<const sockaddr*>(&sa), sizeof(sa));
|
||||
if (bytesSent < 0) {
|
||||
PLOG(ERROR) << "Can't send Netlink message";
|
||||
return false;
|
||||
} else if (size_t(bytesSent) != rawMsg.len()) {
|
||||
LOG(ERROR) << "Can't send Netlink message: truncated message";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Socket::increaseReceiveBuffer(size_t maxSize) {
|
||||
if (maxSize == 0) {
|
||||
LOG(ERROR) << "Maximum receive size should not be zero";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Buffer<nlmsghdr>> Socket::receive(size_t maxSize) {
|
||||
return receiveFrom(maxSize).first;
|
||||
}
|
||||
|
||||
std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size_t maxSize) {
|
||||
if (mFailed) return {std::nullopt, {}};
|
||||
|
||||
if (!increaseReceiveBuffer(maxSize)) return {std::nullopt, {}};
|
||||
|
||||
sockaddr_nl sa = {};
|
||||
socklen_t saLen = sizeof(sa);
|
||||
const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), maxSize, MSG_TRUNC,
|
||||
reinterpret_cast<sockaddr*>(&sa), &saLen);
|
||||
|
||||
if (bytesReceived <= 0) {
|
||||
PLOG(ERROR) << "Failed to receive Netlink message";
|
||||
return {std::nullopt, {}};
|
||||
} else if (size_t(bytesReceived) > maxSize) {
|
||||
PLOG(ERROR) << "Received data larger than maximum receive size: " //
|
||||
<< bytesReceived << " > " << maxSize;
|
||||
return {std::nullopt, {}};
|
||||
}
|
||||
|
||||
Buffer<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(mReceiveBuffer.data()), bytesReceived);
|
||||
if constexpr (kSuperVerbose) {
|
||||
LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
|
||||
}
|
||||
return {msg, sa};
|
||||
}
|
||||
|
||||
bool Socket::receiveAck(uint32_t seq) {
|
||||
const auto nlerr = receive<nlmsgerr>({NLMSG_ERROR});
|
||||
if (!nlerr.has_value()) return false;
|
||||
|
||||
if (nlerr->data.msg.nlmsg_seq != seq) {
|
||||
LOG(ERROR) << "Received ACK for a different message (" << nlerr->data.msg.nlmsg_seq
|
||||
<< ", expected " << seq << "). Multi-message tracking is not implemented.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nlerr->data.error == 0) return true;
|
||||
|
||||
LOG(WARNING) << "Received Netlink error message: " << strerror(-nlerr->data.error);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<Buffer<nlmsghdr>> Socket::receive(const std::set<nlmsgtype_t>& msgtypes,
|
||||
size_t maxSize) {
|
||||
if (mFailed || !increaseReceiveBuffer(maxSize)) return std::nullopt;
|
||||
|
||||
for (const auto rawMsg : *this) {
|
||||
if (msgtypes.count(rawMsg->nlmsg_type) == 0) {
|
||||
LOG(WARNING) << "Received (and ignored) unexpected Netlink message of type "
|
||||
<< rawMsg->nlmsg_type;
|
||||
continue;
|
||||
}
|
||||
|
||||
return rawMsg;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<unsigned> Socket::getPid() {
|
||||
if (mFailed) return std::nullopt;
|
||||
|
||||
sockaddr_nl sa = {};
|
||||
socklen_t sasize = sizeof(sa);
|
||||
if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
|
||||
PLOG(ERROR) << "Failed to get PID of Netlink socket";
|
||||
return std::nullopt;
|
||||
}
|
||||
return sa.nl_pid;
|
||||
}
|
||||
|
||||
pollfd Socket::preparePoll(short events) {
|
||||
return {mFd.get(), events, 0};
|
||||
}
|
||||
|
||||
Socket::receive_iterator::receive_iterator(Socket& socket, bool end)
|
||||
: mSocket(socket), mIsEnd(end) {
|
||||
if (!end) receive();
|
||||
}
|
||||
|
||||
Socket::receive_iterator Socket::receive_iterator::operator++() {
|
||||
CHECK(!mIsEnd) << "Trying to increment end iterator";
|
||||
++mCurrent;
|
||||
if (mCurrent.isEnd()) receive();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Socket::receive_iterator::operator==(const receive_iterator& other) const {
|
||||
if (mIsEnd != other.mIsEnd) return false;
|
||||
if (mIsEnd && other.mIsEnd) return true;
|
||||
return mCurrent == other.mCurrent;
|
||||
}
|
||||
|
||||
const Buffer<nlmsghdr>& Socket::receive_iterator::operator*() const {
|
||||
CHECK(!mIsEnd) << "Trying to dereference end iterator";
|
||||
return *mCurrent;
|
||||
}
|
||||
|
||||
void Socket::receive_iterator::receive() {
|
||||
CHECK(!mIsEnd) << "Trying to receive on end iterator";
|
||||
CHECK(mCurrent.isEnd()) << "Trying to receive without draining previous read";
|
||||
|
||||
const auto buf = mSocket.receive();
|
||||
if (buf.has_value()) {
|
||||
mCurrent = buf->begin();
|
||||
} else {
|
||||
mIsEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
Socket::receive_iterator Socket::begin() {
|
||||
return {*this, false};
|
||||
}
|
||||
|
||||
Socket::receive_iterator Socket::end() {
|
||||
return {*this, true};
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
56
automotive/can/1.0/default/libnl++/common.cpp
Normal file
56
automotive/can/1.0/default/libnl++/common.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 "common.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
unsigned int nametoindex(const std::string& ifname) {
|
||||
const auto ifidx = if_nametoindex(ifname.c_str());
|
||||
if (ifidx != 0) return ifidx;
|
||||
|
||||
if (errno != ENODEV) {
|
||||
PLOG(ERROR) << "if_nametoindex(" << ifname << ") failed";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string printableOnly(std::string str) {
|
||||
const auto isInvalid = [](char c) { return !isprint(c); };
|
||||
std::replace_if(str.begin(), str.end(), isInvalid, '?');
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc) {
|
||||
for (const auto byte : data.getRaw()) {
|
||||
crc ^= byte;
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ 0xA001;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
62
automotive/can/1.0/default/libnl++/common.h
Normal file
62
automotive/can/1.0/default/libnl++/common.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <libnl++/Buffer.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* Returns the index of a given network interface.
|
||||
*
|
||||
* If the syscall to check the index fails with other error than ENODEV, it gets logged and the
|
||||
* return value indicates the interface doesn't exists.
|
||||
*
|
||||
* \param ifname Interface to check
|
||||
* \return Interface index, or 0 if the interface doesn't exist
|
||||
*/
|
||||
unsigned int nametoindex(const std::string& ifname);
|
||||
|
||||
/**
|
||||
* Filter a string against non-printable characters.
|
||||
*
|
||||
* Replaces all non-printable characters with '?'.
|
||||
*
|
||||
* \param str String to filter.
|
||||
* \return Filtered string.
|
||||
*/
|
||||
std::string printableOnly(std::string str);
|
||||
|
||||
/**
|
||||
* Calculates a (optionally running) CRC16 checksum.
|
||||
*
|
||||
* CRC16 isn't a strong checksum, but is good for quick comparison purposes.
|
||||
* One benefit (and also a drawback too) is that all-zero payloads with any length will
|
||||
* always have a checksum of 0x0000.
|
||||
*
|
||||
* \param data Buffer to calculate checksum for
|
||||
* \param crc Previous CRC16 value to continue calculating running checksum
|
||||
* \return CRC16 checksum
|
||||
*/
|
||||
uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc = 0);
|
||||
|
||||
} // namespace android::nl
|
||||
185
automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
Normal file
185
automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <libnl++/Buffer.h>
|
||||
#include <libnl++/types.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* Netlink attribute map.
|
||||
*
|
||||
* This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
|
||||
* message attributes. The class doesn't own the underlying data, so the instance is valid as long
|
||||
* as the source buffer is allocated and unmodified.
|
||||
*
|
||||
* WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
|
||||
* a single instance can only be used by a single thread - the one owning the underlying buffer).
|
||||
*/
|
||||
class Attributes : private Buffer<nlattr> {
|
||||
public:
|
||||
/**
|
||||
* Constructs empty attribute map.
|
||||
*/
|
||||
Attributes();
|
||||
|
||||
/**
|
||||
* Construct attribute map from underlying buffer.
|
||||
*
|
||||
* \param buffer Source buffer pointing at the first attribute.
|
||||
*/
|
||||
Attributes(Buffer<nlattr> buffer);
|
||||
|
||||
/**
|
||||
* Checks, if the map contains given attribute type (key).
|
||||
*
|
||||
* \param attrtype Attribute type (such as IFLA_IFNAME).
|
||||
* \return true if attribute is in the map, false otherwise.
|
||||
*/
|
||||
bool contains(nlattrtype_t attrtype) const;
|
||||
|
||||
/**
|
||||
* Fetches attribute of a given type by copying it.
|
||||
*
|
||||
* While this is quite efficient for simple types, fetching nested attribute creates a new copy
|
||||
* of child attribute map. This may be costly if you calculate the index for child maps multiple
|
||||
* times. Examples below.
|
||||
*
|
||||
* BAD:
|
||||
* ```
|
||||
* const auto flags = msg->attributes.
|
||||
* get<nl::Attributes>(IFLA_AF_SPEC).
|
||||
* get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index lazy-calculated
|
||||
* get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated
|
||||
* const auto& cacheinfo = msg->attributes.
|
||||
* get<nl::Attributes>(IFLA_AF_SPEC). // new instance of IFLA_AF_SPEC index
|
||||
* get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index calculated again
|
||||
* getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // AF_INET6 calculated again
|
||||
* ```
|
||||
*
|
||||
* GOOD:
|
||||
* ```
|
||||
* const auto inet6 = msg->attributes.
|
||||
* get<nl::Attributes>(IFLA_AF_SPEC).
|
||||
* get<nl::Attributes>(AF_INET6);
|
||||
* const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated
|
||||
* const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // index reused
|
||||
* ```
|
||||
*
|
||||
* If the attribute doesn't exists, default value of a given type is returned and warning
|
||||
* spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
|
||||
*
|
||||
* \param attrtype Attribute to fetch.
|
||||
* \return Attribute value.
|
||||
*/
|
||||
template <typename T>
|
||||
T get(nlattrtype_t attrtype) const {
|
||||
const auto buffer = getBuffer(attrtype);
|
||||
if (!buffer.has_value()) {
|
||||
LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
|
||||
return T{};
|
||||
}
|
||||
|
||||
return parse<T>(*buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches underlying buffer of a given attribute.
|
||||
*
|
||||
* This is a low-level access method unlikely to be useful in most cases. Please consider
|
||||
* using #get instead.
|
||||
*
|
||||
* \param attrtype Attribute to fetch
|
||||
* \return Attribute buffer.
|
||||
*/
|
||||
std::optional<Buffer<nlattr>> getBuffer(nlattrtype_t attrtype) const {
|
||||
const auto& ind = index();
|
||||
const auto it = ind.find(attrtype);
|
||||
if (it == ind.end()) return std::nullopt;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a reference to a given attribute's data.
|
||||
*
|
||||
* This method is intended for arbitrary structures not specialized with get(nlattrtype_t)
|
||||
* template and slightly more efficient for larger payloads due to not copying its data.
|
||||
*
|
||||
* If the attribute doesn't exists, a reference to empty value of a given type is returned and
|
||||
* warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
|
||||
*
|
||||
* \param attrtype Attribute to fetch.
|
||||
* \return Reference to the attribute's data.
|
||||
*/
|
||||
template <typename T>
|
||||
const T& getStruct(nlattrtype_t attrtype) const {
|
||||
const auto& ind = index();
|
||||
const auto it = ind.find(attrtype);
|
||||
if (it == ind.end()) {
|
||||
LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
|
||||
static const T empty = {};
|
||||
return empty;
|
||||
}
|
||||
|
||||
const auto& [ok, val] = it->second.data<T>().getFirst();
|
||||
if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T);
|
||||
return val;
|
||||
}
|
||||
|
||||
private:
|
||||
using Index = std::map<nlattrtype_t, Buffer<nlattr>>;
|
||||
|
||||
/**
|
||||
* Attribute index.
|
||||
*
|
||||
* Since this field is not protected by mutex, the use of \see index() dependent methods
|
||||
* (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the
|
||||
* following assumptions:
|
||||
*
|
||||
* 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the
|
||||
* buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the
|
||||
* underlying data buffer.
|
||||
*
|
||||
* 2. Index calculation and access would come with performance penalty never justified in most
|
||||
* or all use cases (see the previous point). Since Index is not a trivially assignable data
|
||||
* structure, it's not possible to use it with atomic types only and avoid mutexes.
|
||||
*/
|
||||
mutable std::optional<Index> mIndex;
|
||||
|
||||
/**
|
||||
* Lazy-calculate and cache index.
|
||||
*
|
||||
* \return Attribute index.
|
||||
*/
|
||||
const Index& index() const;
|
||||
|
||||
/**
|
||||
* Parse attribute data into a specific type.
|
||||
*
|
||||
* \param buf Raw attribute data.
|
||||
* \return Parsed data.
|
||||
*/
|
||||
template <typename T>
|
||||
static T parse(Buffer<nlattr> buf);
|
||||
};
|
||||
|
||||
} // namespace android::nl
|
||||
212
automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
Normal file
212
automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <libnl++/bits.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* Buffer wrapper containing netlink structure (e.g. nlmsghdr, nlattr).
|
||||
*
|
||||
* This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
|
||||
*
|
||||
* While netlink structures contain information about their total length (with payload), they can
|
||||
* not be trusted - the value may either be larger than the buffer message is allocated in or
|
||||
* smaller than the header itself (so it couldn't even fit itself).
|
||||
*
|
||||
* As a solution, Buffer<> keeps track of two lengths (both attribute for header with payload):
|
||||
* - buffer length - how much memory was allocated to a given structure
|
||||
* - declared length - what nlmsg_len or nla_len says how long the structure is
|
||||
*
|
||||
* In most cases buffer length would be larger than declared length (or equal - modulo alignment -
|
||||
* for continuous data). If that's not the case, there is a potential of ouf-of-bounds read which
|
||||
* this template attempts to protect against.
|
||||
*/
|
||||
template <typename T>
|
||||
class Buffer {
|
||||
public:
|
||||
/**
|
||||
* Constructs empty buffer of size 0.
|
||||
*/
|
||||
Buffer() : mData(nullptr), mBufferEnd(nullptr) {}
|
||||
|
||||
/**
|
||||
* Buffer constructor.
|
||||
*
|
||||
* \param data A pointer to the data the Buffer wraps.
|
||||
* \param bufLen Length of the buffer.
|
||||
*/
|
||||
Buffer(const T* data, size_t bufLen) : mData(data), mBufferEnd(pointerAdd(data, bufLen)) {}
|
||||
|
||||
const T* operator->() const {
|
||||
CHECK(firstOk()) << "buffer can't fit the first element's header";
|
||||
return mData;
|
||||
}
|
||||
|
||||
std::pair<bool, const T&> getFirst() const {
|
||||
if (!ok()) {
|
||||
static const T empty = {};
|
||||
return {false, empty};
|
||||
}
|
||||
return {true, *mData};
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the first element of the buffer.
|
||||
*
|
||||
* This is a memory-safe cast operation, useful for reading e.g. uint32_t values
|
||||
* from 1-byte buffer. If the buffer is smaller than the copied type, the rest is
|
||||
* padded with default constructor output (usually zeros).
|
||||
*/
|
||||
T copyFirst() const {
|
||||
T val = {};
|
||||
memcpy(&val, mData, std::min(sizeof(val), remainingLength()));
|
||||
return val;
|
||||
}
|
||||
|
||||
bool firstOk() const { return sizeof(T) <= remainingLength(); }
|
||||
|
||||
template <typename D>
|
||||
const Buffer<D> data(size_t offset = 0) const {
|
||||
return {impl::data<const T, const D>(mData, offset), dataEnd()};
|
||||
}
|
||||
|
||||
template <typename B>
|
||||
std::optional<uintptr_t> getOffset(Buffer<B> inner) const {
|
||||
const auto selfStart = uintptr_t(mData);
|
||||
const auto selfEnd = uintptr_t(mBufferEnd);
|
||||
const auto innerStart = uintptr_t(inner.mData);
|
||||
const auto innerEnd = uintptr_t(inner.mBufferEnd);
|
||||
|
||||
if (innerStart < selfStart || innerEnd > selfEnd) return std::nullopt;
|
||||
|
||||
return innerStart - selfStart;
|
||||
}
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
iterator() : mCurrent(nullptr, size_t(0)) {
|
||||
CHECK(isEnd()) << "end() iterator should indicate it's beyond end";
|
||||
}
|
||||
iterator(const Buffer<T>& buf) : mCurrent(buf) {}
|
||||
|
||||
iterator operator++() {
|
||||
// mBufferEnd stays the same
|
||||
mCurrent.mData = reinterpret_cast<const T*>( //
|
||||
uintptr_t(mCurrent.mData) + impl::align(mCurrent.declaredLength()));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& other) const {
|
||||
// all iterators beyond end are the same
|
||||
if (isEnd() && other.isEnd()) return true;
|
||||
|
||||
return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
|
||||
}
|
||||
|
||||
const Buffer<T>& operator*() const { return mCurrent; }
|
||||
|
||||
bool isEnd() const { return !mCurrent.ok(); }
|
||||
|
||||
protected:
|
||||
Buffer<T> mCurrent;
|
||||
};
|
||||
iterator begin() const { return {*this}; }
|
||||
iterator end() const { return {}; }
|
||||
|
||||
class raw_iterator : public iterator {
|
||||
public:
|
||||
iterator operator++() {
|
||||
this->mCurrent.mData++; // ignore alignment
|
||||
return *this;
|
||||
}
|
||||
const T& operator*() const { return *this->mCurrent.mData; }
|
||||
};
|
||||
|
||||
class raw_view {
|
||||
public:
|
||||
raw_view(const Buffer<T>& buffer) : mBuffer(buffer) {}
|
||||
raw_iterator begin() const { return {mBuffer}; }
|
||||
raw_iterator end() const { return {}; }
|
||||
|
||||
const T* ptr() const { return mBuffer.mData; }
|
||||
size_t len() const { return mBuffer.remainingLength(); }
|
||||
|
||||
private:
|
||||
const Buffer<T> mBuffer;
|
||||
};
|
||||
|
||||
raw_view getRaw() const { return {*this}; }
|
||||
|
||||
private:
|
||||
const T* mData;
|
||||
const void* mBufferEnd;
|
||||
|
||||
Buffer(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
|
||||
|
||||
bool ok() const { return declaredLength() <= remainingLength(); }
|
||||
|
||||
// to be specialized individually for each T with payload after a header
|
||||
inline size_t declaredLengthImpl() const { return sizeof(T); }
|
||||
|
||||
size_t declaredLength() const {
|
||||
// We can't even fit a header, so let's return some absurd high value to trip off
|
||||
// buffer overflow checks.
|
||||
static constexpr size_t badHeaderLength = std::numeric_limits<size_t>::max() / 2;
|
||||
|
||||
if (sizeof(T) > remainingLength()) return badHeaderLength;
|
||||
const auto len = declaredLengthImpl();
|
||||
if (sizeof(T) > len) return badHeaderLength;
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t remainingLength() const {
|
||||
auto len = intptr_t(mBufferEnd) - intptr_t(mData);
|
||||
return (len >= 0) ? len : 0;
|
||||
}
|
||||
|
||||
const void* dataEnd() const {
|
||||
auto declaredEnd = pointerAdd(mData, declaredLength());
|
||||
return std::min(declaredEnd, mBufferEnd);
|
||||
}
|
||||
|
||||
static const void* pointerAdd(const void* ptr, size_t len) {
|
||||
return reinterpret_cast<const void*>(uintptr_t(ptr) + len);
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
friend class Buffer; // calling private constructor of data buffers
|
||||
};
|
||||
|
||||
template <>
|
||||
inline size_t Buffer<nlmsghdr>::declaredLengthImpl() const {
|
||||
return mData->nlmsg_len;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline size_t Buffer<nlattr>::declaredLengthImpl() const {
|
||||
return mData->nla_len;
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
101
automotive/can/1.0/default/libnl++/include/libnl++/Message.h
Normal file
101
automotive/can/1.0/default/libnl++/include/libnl++/Message.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libnl++/Attributes.h>
|
||||
#include <libnl++/Buffer.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* In-place Netlink message parser.
|
||||
*
|
||||
* This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
|
||||
* message contents. The class doesn't own the underlying data, so the instance is valid as long as
|
||||
* the source buffer is allocated and unmodified.
|
||||
*
|
||||
* WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
|
||||
* a single instance can only be used by a single thread - the one owning the underlying buffer).
|
||||
*/
|
||||
template <typename T>
|
||||
class Message {
|
||||
public:
|
||||
/**
|
||||
* Validate buffer contents as a message carrying T data and create instance of parsed message.
|
||||
*
|
||||
* \param buf Buffer containing the message.
|
||||
* \return Parsed message or nullopt, if the buffer data is invalid.
|
||||
*/
|
||||
static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf) {
|
||||
const auto& [nlOk, nlHeader] = buf.getFirst();
|
||||
if (!nlOk) return std::nullopt;
|
||||
|
||||
const auto& [dataOk, dataHeader] = buf.data<T>().getFirst();
|
||||
if (!dataOk) return std::nullopt;
|
||||
|
||||
const auto attributes = buf.data<nlattr>(sizeof(T));
|
||||
|
||||
return Message<T>(nlHeader, dataHeader, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate buffer contents as a message of a given type and create instance of parsed message.
|
||||
*
|
||||
* \param buf Buffer containing the message.
|
||||
* \param msgtypes Acceptable message types (within a specific Netlink protocol)
|
||||
* \return Parsed message or nullopt, if the buffer data is invalid or message type
|
||||
* doesn't match.
|
||||
*/
|
||||
static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf,
|
||||
const std::set<nlmsgtype_t>& msgtypes) {
|
||||
const auto& [nlOk, nlHeader] = buf.getFirst(); // we're doing it twice, but it's fine
|
||||
if (!nlOk) return std::nullopt;
|
||||
|
||||
if (msgtypes.count(nlHeader.nlmsg_type) == 0) return std::nullopt;
|
||||
|
||||
return parse(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Netlink message header.
|
||||
*
|
||||
* This is a generic Netlink header containing information such as message flags.
|
||||
*/
|
||||
const nlmsghdr& header;
|
||||
|
||||
/**
|
||||
* Netlink message data.
|
||||
*
|
||||
* This is a payload specific to a given message type.
|
||||
*/
|
||||
const T& data;
|
||||
|
||||
/**
|
||||
* Netlink message attributes.
|
||||
*/
|
||||
const Attributes attributes;
|
||||
|
||||
const T* operator->() const { return &data; }
|
||||
|
||||
private:
|
||||
Message(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes)
|
||||
: header(nlHeader), data(dataHeader), attributes(attributes) {}
|
||||
};
|
||||
|
||||
} // namespace android::nl
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <android-base/macros.h>
|
||||
#include <libnl++/Buffer.h>
|
||||
#include <libnl++/types.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
class MessageFactoryBase {
|
||||
protected:
|
||||
static nlattr* add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
|
||||
size_t dataLen);
|
||||
static void closeNested(nlmsghdr* msg, nlattr* nested);
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
|
||||
*
|
||||
* \param T Message payload type (such as ifinfomsg).
|
||||
* \param BUFSIZE how much space to reserve for attributes.
|
||||
*/
|
||||
template <class T, unsigned int BUFSIZE = 128>
|
||||
class MessageFactory : private MessageFactoryBase {
|
||||
struct alignas(NLMSG_ALIGNTO) Message {
|
||||
nlmsghdr header;
|
||||
T data;
|
||||
uint8_t attributesBuffer[BUFSIZE];
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create empty message.
|
||||
*
|
||||
* \param type Message type (such as RTM_NEWLINK).
|
||||
* \param flags Message flags (such as NLM_F_REQUEST).
|
||||
*/
|
||||
MessageFactory(nlmsgtype_t type, uint16_t flags)
|
||||
: header(mMessage.header), data(mMessage.data) {
|
||||
mMessage.header.nlmsg_len = offsetof(Message, attributesBuffer);
|
||||
mMessage.header.nlmsg_type = type;
|
||||
mMessage.header.nlmsg_flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Netlink message header.
|
||||
*
|
||||
* This is a generic Netlink header containing information such as message flags.
|
||||
*/
|
||||
nlmsghdr& header;
|
||||
|
||||
/**
|
||||
* Netlink message data.
|
||||
*
|
||||
* This is a payload specific to a given message type.
|
||||
*/
|
||||
T& data;
|
||||
|
||||
T* operator->() { return &mMessage.data; }
|
||||
|
||||
/**
|
||||
* Build netlink message.
|
||||
*
|
||||
* In fact, this operation is almost a no-op, since the factory builds the message in a single
|
||||
* buffer, using native data structures.
|
||||
*
|
||||
* A likely failure case is when the BUFSIZE template parameter is too small to acommodate
|
||||
* added attributes. In such a case, please increase this parameter.
|
||||
*
|
||||
* \return Netlink message or std::nullopt in case of failure.
|
||||
*/
|
||||
std::optional<Buffer<nlmsghdr>> build() const {
|
||||
if (!mIsGood) return std::nullopt;
|
||||
return {{&mMessage.header, mMessage.header.nlmsg_len}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an attribute of a trivially copyable type.
|
||||
*
|
||||
* Template specializations may extend this function for other types, such as std::string.
|
||||
*
|
||||
* If this method fails (i.e. due to insufficient space), a warning will be printed to the log
|
||||
* and the message will be marked as bad, causing later \see build call to fail.
|
||||
*
|
||||
* \param type attribute type (such as IFLA_IFNAME)
|
||||
* \param attr attribute data
|
||||
*/
|
||||
template <class A>
|
||||
void add(nlattrtype_t type, const A& attr) {
|
||||
add(type, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
template <>
|
||||
void add(nlattrtype_t type, const std::string& s) {
|
||||
add(type, s.c_str(), s.size() + 1);
|
||||
}
|
||||
|
||||
/** 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() { closeNested(&mReq.mMessage.header, mAttr); }
|
||||
|
||||
private:
|
||||
MessageFactory& mReq;
|
||||
nlattr* mAttr;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NestedGuard);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add nested attribute.
|
||||
*
|
||||
* The returned object is a guard for auto-nesting children inside the argument attribute.
|
||||
* When the guard object goes out of scope, the nesting attribute is closed.
|
||||
*
|
||||
* Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
|
||||
* inside IFLA_LINKINFO:
|
||||
* MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
|
||||
* {
|
||||
* auto linkinfo = req.addNested(IFLA_LINKINFO);
|
||||
* req.add(IFLA_INFO_KIND, "can");
|
||||
* {
|
||||
* auto infodata = req.addNested(IFLA_INFO_DATA);
|
||||
* req.add(IFLA_CAN_BITTIMING, bitTimingStruct);
|
||||
* }
|
||||
* }
|
||||
* // use req
|
||||
*
|
||||
* \param type attribute type (such as IFLA_LINKINFO)
|
||||
*/
|
||||
NestedGuard addNested(nlattrtype_t type) { return {*this, type}; }
|
||||
|
||||
private:
|
||||
Message mMessage = {};
|
||||
bool mIsGood = true;
|
||||
|
||||
nlattr* add(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;
|
||||
return attr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace android::nl
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libnl++/Message.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* In-place message mutator.
|
||||
*
|
||||
* Useful for making small changes (such as adjusting const-sized attributes or struct fields)
|
||||
* efficiently and in-place. However, if you need to rebuild the message (e.g. to modify variable
|
||||
* sized attributes or add/remove them), you need to use MessageFactory instead.
|
||||
*/
|
||||
class MessageMutator {
|
||||
public:
|
||||
/**
|
||||
* Construct message mutator object from editable buffer.
|
||||
*/
|
||||
MessageMutator(nlmsghdr* buffer, size_t totalLen);
|
||||
|
||||
nlmsghdr* operator->() const;
|
||||
operator Buffer<nlmsghdr>() const;
|
||||
|
||||
/**
|
||||
* Read current attribute value.
|
||||
*
|
||||
* \param Read-only attribute buffer.
|
||||
* \returns Attribute value.
|
||||
*/
|
||||
uint64_t read(Buffer<nlattr> attr) const;
|
||||
|
||||
/**
|
||||
* Write new attribute value.
|
||||
*
|
||||
* \param Read-only attribute buffer.
|
||||
* \param val New value to set.
|
||||
*/
|
||||
void write(Buffer<nlattr> attr, uint64_t val) const;
|
||||
|
||||
private:
|
||||
const Buffer<nlmsghdr> mConstBuffer;
|
||||
nlmsghdr* mMutableBuffer;
|
||||
};
|
||||
|
||||
} // namespace android::nl
|
||||
235
automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
Normal file
235
automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <android-base/macros.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <libnl++/Buffer.h>
|
||||
#include <libnl++/Message.h>
|
||||
#include <libnl++/MessageFactory.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* A wrapper around AF_NETLINK sockets.
|
||||
*
|
||||
* This class is not thread safe to use a single instance between multiple threads, but it's fine to
|
||||
* use multiple instances over multiple threads.
|
||||
*/
|
||||
class Socket {
|
||||
public:
|
||||
static constexpr size_t defaultReceiveSize = 8192;
|
||||
|
||||
/**
|
||||
* Socket constructor.
|
||||
*
|
||||
* \param protocol the Netlink protocol to use.
|
||||
* \param pid port id. Default value of 0 allows the kernel to assign us a unique pid.
|
||||
* (NOTE: this is NOT the same as process id).
|
||||
* \param groups Netlink multicast groups to listen to. This is a 32-bit bitfield, where each
|
||||
* bit is a different group. Default value of 0 means no groups are selected.
|
||||
* See man netlink.7.
|
||||
* for more details.
|
||||
*/
|
||||
Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
|
||||
|
||||
/**
|
||||
* Send Netlink message with incremented sequence number to the Kernel.
|
||||
*
|
||||
* \param msg Message to send. Its sequence number will be updated.
|
||||
* \return true, if succeeded.
|
||||
*/
|
||||
template <typename T, unsigned BUFSIZE>
|
||||
bool send(MessageFactory<T, BUFSIZE>& req) {
|
||||
sockaddr_nl sa = {};
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_pid = 0; // Kernel
|
||||
return send(req, sa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Netlink message with incremented sequence number.
|
||||
*
|
||||
* \param msg Message to send. Its sequence number will be updated.
|
||||
* \param sa Destination address.
|
||||
* \return true, if succeeded.
|
||||
*/
|
||||
template <typename T, unsigned BUFSIZE>
|
||||
bool send(MessageFactory<T, BUFSIZE>& req, const sockaddr_nl& sa) {
|
||||
req.header.nlmsg_seq = mSeq + 1;
|
||||
|
||||
const auto msg = req.build();
|
||||
if (!msg.has_value()) return false;
|
||||
|
||||
return send(*msg, sa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Netlink message.
|
||||
*
|
||||
* \param msg Message to send.
|
||||
* \param sa Destination address.
|
||||
* \return true, if succeeded.
|
||||
*/
|
||||
bool send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa);
|
||||
|
||||
/**
|
||||
* Receive one or multiple Netlink messages.
|
||||
*
|
||||
* WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
|
||||
* call to the read function or until deallocation of Socket instance.
|
||||
*
|
||||
* \param maxSize Maximum total size of received messages
|
||||
* \return Buffer view with message data, std::nullopt on error.
|
||||
*/
|
||||
std::optional<Buffer<nlmsghdr>> receive(size_t maxSize = defaultReceiveSize);
|
||||
|
||||
/**
|
||||
* Receive one or multiple Netlink messages and the sender process address.
|
||||
*
|
||||
* WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
|
||||
* call to the read function or until deallocation of Socket instance.
|
||||
*
|
||||
* \param maxSize Maximum total size of received messages.
|
||||
* \return A pair (for use with structured binding) containing:
|
||||
* - buffer view with message data, std::nullopt on error;
|
||||
* - sender process address.
|
||||
*/
|
||||
std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> receiveFrom(
|
||||
size_t maxSize = defaultReceiveSize);
|
||||
|
||||
/**
|
||||
* Receive matching Netlink message of a given payload type.
|
||||
*
|
||||
* This method should be used if the caller expects exactly one incoming message of exactly
|
||||
* given type (such as ACK). If there is a use case to handle multiple types of messages,
|
||||
* please use receive(size_t) directly and iterate through potential multipart messages.
|
||||
*
|
||||
* If this method is used in such an environment, it will only return the first matching message
|
||||
* from multipart packet and will issue warnings on messages that do not match.
|
||||
*
|
||||
* \param msgtypes Expected message types (such as NLMSG_ERROR).
|
||||
* \param maxSize Maximum total size of received messages.
|
||||
* \return Parsed message or std::nullopt in case of error.
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<Message<T>> receive(const std::set<nlmsgtype_t>& msgtypes,
|
||||
size_t maxSize = defaultReceiveSize) {
|
||||
const auto msg = receive(msgtypes, maxSize);
|
||||
if (!msg.has_value()) return std::nullopt;
|
||||
|
||||
const auto parsed = Message<T>::parse(*msg);
|
||||
if (!parsed.has_value()) {
|
||||
LOG(WARNING) << "Received matching Netlink message, but couldn't parse it";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive Netlink ACK message.
|
||||
*
|
||||
* \param req Message to match sequence number against.
|
||||
* \return true if received ACK message, false in case of error.
|
||||
*/
|
||||
template <typename T, unsigned BUFSIZE>
|
||||
bool receiveAck(MessageFactory<T, BUFSIZE>& req) {
|
||||
return receiveAck(req.header.nlmsg_seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive Netlink ACK message.
|
||||
*
|
||||
* \param seq Sequence number of message to ACK.
|
||||
* \return true if received ACK message, false in case of error.
|
||||
*/
|
||||
bool receiveAck(uint32_t seq);
|
||||
|
||||
/**
|
||||
* Fetches the socket PID.
|
||||
*
|
||||
* \return PID that socket is bound to or std::nullopt.
|
||||
*/
|
||||
std::optional<unsigned> getPid();
|
||||
|
||||
/**
|
||||
* Creates a pollfd object for the socket.
|
||||
*
|
||||
* \param events Value for pollfd.events.
|
||||
* \return A populated pollfd object.
|
||||
*/
|
||||
pollfd preparePoll(short events = 0);
|
||||
|
||||
/**
|
||||
* Live iterator continuously receiving messages from Netlink socket.
|
||||
*
|
||||
* Iteration ends when socket fails to receive a buffer.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
|
||||
* for (const auto rawMsg : sock) {
|
||||
* const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
|
||||
* if (!msg.has_value()) continue;
|
||||
*
|
||||
* LOG(INFO) << msg->attributes.get<std::string>(IFLA_IFNAME)
|
||||
* << " is " << ((msg->data.ifi_flags & IFF_UP) ? "up" : "down");
|
||||
* }
|
||||
* LOG(FATAL) << "Failed to read from Netlink socket";
|
||||
* ```
|
||||
*/
|
||||
class receive_iterator {
|
||||
public:
|
||||
receive_iterator(Socket& socket, bool end);
|
||||
|
||||
receive_iterator operator++();
|
||||
bool operator==(const receive_iterator& other) const;
|
||||
const Buffer<nlmsghdr>& operator*() const;
|
||||
|
||||
private:
|
||||
Socket& mSocket;
|
||||
bool mIsEnd;
|
||||
Buffer<nlmsghdr>::iterator mCurrent;
|
||||
|
||||
void receive();
|
||||
};
|
||||
receive_iterator begin();
|
||||
receive_iterator end();
|
||||
|
||||
private:
|
||||
const int mProtocol;
|
||||
base::unique_fd mFd;
|
||||
std::vector<uint8_t> mReceiveBuffer;
|
||||
|
||||
bool mFailed = false;
|
||||
uint32_t mSeq = 0;
|
||||
|
||||
bool increaseReceiveBuffer(size_t maxSize);
|
||||
std::optional<Buffer<nlmsghdr>> receive(const std::set<nlmsgtype_t>& msgtypes, size_t maxSize);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Socket);
|
||||
};
|
||||
|
||||
} // namespace android::nl
|
||||
54
automotive/can/1.0/default/libnl++/include/libnl++/bits.h
Normal file
54
automotive/can/1.0/default/libnl++/include/libnl++/bits.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
namespace android::nl::impl {
|
||||
|
||||
// The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h.
|
||||
|
||||
/**
|
||||
* Equivalent to NLMSG_ALIGNTO.
|
||||
*/
|
||||
constexpr size_t alignto = NLMSG_ALIGNTO;
|
||||
static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
|
||||
|
||||
/**
|
||||
* Equivalent to NLMSG_ALIGN(len).
|
||||
*/
|
||||
constexpr size_t align(size_t len) {
|
||||
return (len + alignto - 1) & ~(alignto - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to NLMSG_SPACE(len).
|
||||
*/
|
||||
template <typename H>
|
||||
constexpr size_t space(size_t len) {
|
||||
return align(align(sizeof(H)) + len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset).
|
||||
*/
|
||||
template <typename H, typename D>
|
||||
constexpr D* data(H* header, size_t offset = 0) {
|
||||
return reinterpret_cast<D*>(uintptr_t(header) + space<H>(offset));
|
||||
}
|
||||
|
||||
} // namespace android::nl::impl
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libnl++/Buffer.h>
|
||||
#include <libnl++/Message.h>
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace android::nl::generic {
|
||||
|
||||
/**
|
||||
* Tracker of Netlink family ID registrations.
|
||||
*/
|
||||
class FamilyTracker {
|
||||
public:
|
||||
/**
|
||||
* Try parsing NL80211 message.
|
||||
*
|
||||
* Proper parsing of NL80211 nessages requires prior parsing of control message for Generic
|
||||
* Netlink protocol.
|
||||
*
|
||||
* \param msg Message to parse
|
||||
* \returns Parsed NL80211 message or std::nullopt if it wasn't one
|
||||
*/
|
||||
std::optional<Message<genlmsghdr>> parseNl80211(Buffer<nlmsghdr> msg);
|
||||
|
||||
private:
|
||||
/* For efficiency, we use a single hardcoded family ID. However, if we supported multiple family
|
||||
* types, this should probably be a map.
|
||||
*/
|
||||
std::optional<uint16_t> mNl80211FamilyId;
|
||||
|
||||
/**
|
||||
* Track Generic protocol messages.
|
||||
*
|
||||
* This method is looking for family registration messages.
|
||||
*
|
||||
* \param msg Message to track
|
||||
* \returns True, if the message was a control message (regardless of carrying
|
||||
* family info or not)
|
||||
*/
|
||||
bool track(const Buffer<nlmsghdr>& msg);
|
||||
};
|
||||
|
||||
} // namespace android::nl::generic
|
||||
37
automotive/can/1.0/default/libnl++/include/libnl++/printer.h
Normal file
37
automotive/can/1.0/default/libnl++/include/libnl++/printer.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libnl++/Buffer.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
/**
|
||||
* Stringify a Netlink message.
|
||||
*
|
||||
* \param hdr Pointer to the message(s) to print.
|
||||
* \param protocol Which Netlink protocol hdr uses.
|
||||
* \param printPayload True will stringify message data, false will only stringify the header(s).
|
||||
* \return Stringified message.
|
||||
*/
|
||||
std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = true);
|
||||
|
||||
} // namespace android::nl
|
||||
26
automotive/can/1.0/default/libnl++/include/libnl++/types.h
Normal file
26
automotive/can/1.0/default/libnl++/include/libnl++/types.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
typedef decltype(nlmsghdr::nlmsg_type) nlmsgtype_t;
|
||||
typedef decltype(nlattr::nla_type) nlattrtype_t;
|
||||
|
||||
} // namespace android::nl
|
||||
217
automotive/can/1.0/default/libnl++/printer.cpp
Normal file
217
automotive/can/1.0/default/libnl++/printer.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libnl++/printer.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "protocols/all.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <libnl++/Buffer.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace android::nl {
|
||||
|
||||
static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::MessageGenre genre) {
|
||||
bool first = true;
|
||||
auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) {
|
||||
if ((nlmsg_flags & flag) != flag) return;
|
||||
nlmsg_flags &= ~flag;
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
ss << '|';
|
||||
}
|
||||
|
||||
ss << name;
|
||||
};
|
||||
|
||||
printFlag(NLM_F_REQUEST, "REQUEST");
|
||||
printFlag(NLM_F_MULTI, "MULTI");
|
||||
printFlag(NLM_F_ACK, "ACK");
|
||||
printFlag(NLM_F_ECHO, "ECHO");
|
||||
printFlag(NLM_F_DUMP_INTR, "DUMP_INTR");
|
||||
printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
|
||||
|
||||
switch (genre) {
|
||||
case protocols::MessageGenre::Unknown:
|
||||
break;
|
||||
case protocols::MessageGenre::Get:
|
||||
printFlag(NLM_F_DUMP, "DUMP"); // ROOT | MATCH
|
||||
printFlag(NLM_F_ROOT, "ROOT");
|
||||
printFlag(NLM_F_MATCH, "MATCH");
|
||||
printFlag(NLM_F_ATOMIC, "ATOMIC");
|
||||
break;
|
||||
case protocols::MessageGenre::New:
|
||||
printFlag(NLM_F_REPLACE, "REPLACE");
|
||||
printFlag(NLM_F_EXCL, "EXCL");
|
||||
printFlag(NLM_F_CREATE, "CREATE");
|
||||
printFlag(NLM_F_APPEND, "APPEND");
|
||||
break;
|
||||
case protocols::MessageGenre::Delete:
|
||||
printFlag(NLM_F_NONREC, "NONREC");
|
||||
break;
|
||||
case protocols::MessageGenre::Ack:
|
||||
printFlag(NLM_F_CAPPED, "CAPPED");
|
||||
printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
|
||||
break;
|
||||
}
|
||||
|
||||
if (nlmsg_flags != 0) {
|
||||
if (!first) ss << '|';
|
||||
ss << std::hex << nlmsg_flags << std::dec;
|
||||
}
|
||||
}
|
||||
|
||||
static void toStream(std::stringstream& ss, const Buffer<uint8_t> data) {
|
||||
const auto rawData = data.getRaw();
|
||||
const auto dataLen = rawData.len();
|
||||
ss << std::hex;
|
||||
int i = 0;
|
||||
for (const auto byte : rawData) {
|
||||
if (i % 16 == 0 && dataLen > 16) {
|
||||
ss << std::endl << ' ' << std::dec << std::setw(4) << i << std::hex;
|
||||
}
|
||||
if (i++ > 0 || dataLen > 16) ss << ' ';
|
||||
ss << std::setw(2) << unsigned(byte);
|
||||
}
|
||||
ss << std::dec;
|
||||
if (dataLen > 16) ss << std::endl;
|
||||
}
|
||||
|
||||
static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
|
||||
const protocols::AttributeMap& attrMap) {
|
||||
using DataType = protocols::AttributeDefinition::DataType;
|
||||
using Flags = protocols::AttributeDefinition::Flags;
|
||||
const auto attrtype = attrMap[attr->nla_type];
|
||||
|
||||
ss << attrtype.name;
|
||||
|
||||
if (attrtype.dataType == DataType::Flag && attr.data<uint8_t>().getRaw().len() == 0) return;
|
||||
ss << ": ";
|
||||
|
||||
if (attrtype.flags == Flags::Verbose) {
|
||||
const auto raw = attr.data<uint8_t>();
|
||||
ss << "{len=" << raw.getRaw().len();
|
||||
ss << ", crc=" << std::hex << std::setw(4) << crc16(raw) << std::dec;
|
||||
ss << "}";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (attrtype.dataType) {
|
||||
case DataType::Raw:
|
||||
case DataType::Flag:
|
||||
toStream(ss, attr.data<uint8_t>());
|
||||
break;
|
||||
case DataType::Nested: {
|
||||
ss << '{';
|
||||
bool first = true;
|
||||
for (const auto childattr : attr.data<nlattr>()) {
|
||||
if (!first) ss << ", ";
|
||||
first = false;
|
||||
toStream(ss, childattr, std::get<protocols::AttributeMap>(attrtype.ops));
|
||||
}
|
||||
ss << '}';
|
||||
break;
|
||||
}
|
||||
case DataType::StringNul:
|
||||
case DataType::String: {
|
||||
const auto str = attr.data<char>().getRaw();
|
||||
auto len = str.len();
|
||||
if (attrtype.dataType == DataType::StringNul && len > 0 && str.ptr()[len - 1] == '\0') {
|
||||
len--;
|
||||
}
|
||||
|
||||
ss << '"' << printableOnly({str.ptr(), len}) << '"';
|
||||
break;
|
||||
}
|
||||
case DataType::Uint:
|
||||
ss << attr.data<uint64_t>().copyFirst();
|
||||
break;
|
||||
case DataType::Struct: {
|
||||
const auto structToStream =
|
||||
std::get<protocols::AttributeDefinition::ToStream>(attrtype.ops);
|
||||
structToStream(ss, attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload) {
|
||||
if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::setfill('0');
|
||||
|
||||
auto protocolMaybe = protocols::get(protocol);
|
||||
if (!protocolMaybe.has_value()) {
|
||||
ss << "nlmsg{protocol=" << protocol << "}";
|
||||
return ss.str();
|
||||
}
|
||||
protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
|
||||
|
||||
auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
|
||||
const auto msgDetails =
|
||||
protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
|
||||
|
||||
if (msgDescMaybe.has_value()) msgDescMaybe->get().track(hdr);
|
||||
|
||||
ss << "nlmsg{" << protocolDescr.getName() << " ";
|
||||
|
||||
ss << "hdr={";
|
||||
ss << "type=" << msgDetails.name;
|
||||
if (hdr->nlmsg_flags != 0) {
|
||||
ss << ", flags=";
|
||||
flagsToStream(ss, hdr->nlmsg_flags, msgDetails.genre);
|
||||
}
|
||||
if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq;
|
||||
if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid;
|
||||
ss << ", len=" << hdr->nlmsg_len;
|
||||
ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec;
|
||||
ss << '}';
|
||||
|
||||
if (!printPayload) return ss.str();
|
||||
ss << ' ';
|
||||
|
||||
if (!msgDescMaybe.has_value()) {
|
||||
toStream(ss, hdr.data<uint8_t>());
|
||||
} else {
|
||||
const protocols::MessageDescriptor& msgDesc = *msgDescMaybe;
|
||||
msgDesc.dataToStream(ss, hdr);
|
||||
|
||||
bool first = true;
|
||||
for (auto attr : hdr.data<nlattr>(msgDesc.getContentsSize())) {
|
||||
if (first) {
|
||||
ss << " attributes: {";
|
||||
first = false;
|
||||
} else {
|
||||
ss << ", ";
|
||||
}
|
||||
toStream(ss, attr, msgDesc.getAttributeMap());
|
||||
}
|
||||
if (!first) ss << '}';
|
||||
}
|
||||
|
||||
ss << "}";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace android::nl
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MessageDefinition.h"
|
||||
|
||||
namespace android::nl::protocols {
|
||||
|
||||
AttributeMap::AttributeMap(const std::initializer_list<value_type> attrTypes)
|
||||
: std::map<std::optional<nlattrtype_t>, AttributeDefinition>(attrTypes) {}
|
||||
|
||||
const AttributeDefinition AttributeMap::operator[](nlattrtype_t nla_type) const {
|
||||
if (count(nla_type) == 0) {
|
||||
if (count(std::nullopt) == 0) return {std::to_string(nla_type)};
|
||||
|
||||
auto definition = find(std::nullopt)->second;
|
||||
definition.name += std::to_string(nla_type);
|
||||
return definition;
|
||||
}
|
||||
return find(nla_type)->second;
|
||||
}
|
||||
|
||||
MessageDescriptor::MessageDescriptor(const std::string& name,
|
||||
const MessageDetailsMap&& messageDetails,
|
||||
const AttributeMap&& attrTypes, size_t contentsSize)
|
||||
: mName(name),
|
||||
mContentsSize(contentsSize),
|
||||
mMessageDetails(messageDetails),
|
||||
mAttributeMap(attrTypes) {}
|
||||
|
||||
MessageDescriptor::~MessageDescriptor() {}
|
||||
|
||||
size_t MessageDescriptor::getContentsSize() const {
|
||||
return mContentsSize;
|
||||
}
|
||||
|
||||
const MessageDescriptor::MessageDetailsMap& MessageDescriptor::getMessageDetailsMap() const {
|
||||
return mMessageDetails;
|
||||
}
|
||||
|
||||
const AttributeMap& MessageDescriptor::getAttributeMap() const {
|
||||
return mAttributeMap;
|
||||
}
|
||||
|
||||
MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(nlmsgtype_t msgtype) const {
|
||||
const auto it = mMessageDetails.find(msgtype);
|
||||
if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::Unknown};
|
||||
return it->second;
|
||||
}
|
||||
|
||||
MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
|
||||
const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe,
|
||||
nlmsgtype_t msgtype) {
|
||||
if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
|
||||
return {std::to_string(msgtype), protocols::MessageGenre::Unknown};
|
||||
}
|
||||
|
||||
void MessageDescriptor::track(const Buffer<nlmsghdr> /* hdr */) {}
|
||||
|
||||
} // namespace android::nl::protocols
|
||||
203
automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
Normal file
203
automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libnl++/Buffer.h>
|
||||
#include <libnl++/types.h>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <variant>
|
||||
|
||||
namespace android::nl::protocols {
|
||||
|
||||
struct AttributeDefinition;
|
||||
|
||||
/**
|
||||
* Mapping between nlattrtype_t identifier and attribute definition.
|
||||
*
|
||||
* The map contains values for all nlattrtype_t identifiers - if some is missing, a generic
|
||||
* definition with a identifier as its name will be generated.
|
||||
*
|
||||
* It's possible to define a default attribute to return instead of to_string of its identifier
|
||||
* (useful for nested attribute lists). In such case, an entry with id=std::nullopt needs to be
|
||||
* present in the map.
|
||||
*/
|
||||
class AttributeMap : private std::map<std::optional<nlattrtype_t>, AttributeDefinition> {
|
||||
public:
|
||||
using std::map<std::optional<nlattrtype_t>, AttributeDefinition>::value_type;
|
||||
|
||||
AttributeMap(const std::initializer_list<value_type> attrTypes);
|
||||
|
||||
const AttributeDefinition operator[](nlattrtype_t nla_type) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attribute definition.
|
||||
*
|
||||
* Describes the name and type (optionally sub types, in case of Nested attribute)
|
||||
* for a given message attribute.
|
||||
*/
|
||||
struct AttributeDefinition {
|
||||
enum class DataType : uint8_t {
|
||||
/**
|
||||
* Binary blob (or attribute of unknown type).
|
||||
*/
|
||||
Raw,
|
||||
|
||||
/**
|
||||
* Nested attribute (with or without NLA_F_NESTED).
|
||||
*/
|
||||
Nested,
|
||||
|
||||
/**
|
||||
* Non-null terminated string.
|
||||
*
|
||||
* The length of the string is determined by the size of an attribute.
|
||||
*/
|
||||
String,
|
||||
|
||||
/**
|
||||
* Null terminated string.
|
||||
*/
|
||||
StringNul,
|
||||
|
||||
/**
|
||||
* Unsigned integer of size 8, 16, 32 or 64 bits.
|
||||
*/
|
||||
Uint,
|
||||
|
||||
/**
|
||||
* Structure which printer is defined in ops ToStream variant.
|
||||
*/
|
||||
Struct,
|
||||
|
||||
/**
|
||||
* Flag attribute.
|
||||
*
|
||||
* The attribute doesn't have any contents. The flag is set when the attribute is present,
|
||||
* it's not when it's absent from attribute list.
|
||||
*/
|
||||
Flag,
|
||||
};
|
||||
enum class Flags : uint8_t {
|
||||
Verbose = (1 << 0),
|
||||
};
|
||||
using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>;
|
||||
|
||||
std::string name;
|
||||
DataType dataType = DataType::Raw;
|
||||
std::variant<AttributeMap, ToStream> ops = AttributeMap{};
|
||||
|
||||
/**
|
||||
* Attribute flags.
|
||||
*
|
||||
* It's not really a bitmask flag set (since you are not supposed to compare enum class by
|
||||
* bitmask), but std::set<Flags> bumps compile time from 16s to 3m. Let's leave it as-is for
|
||||
* now and revisit if we get some flags that can be used in pairs. When it happens, review all
|
||||
* uses of the flags field to include the "&" operator and not "==".
|
||||
*/
|
||||
Flags flags = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* General message type's kind.
|
||||
*
|
||||
* For example, RTM_NEWLINK is a NEW kind. For details, please see "Flags values"
|
||||
* section in linux/netlink.h.
|
||||
*/
|
||||
enum class MessageGenre {
|
||||
Unknown,
|
||||
Get,
|
||||
New,
|
||||
Delete,
|
||||
Ack,
|
||||
};
|
||||
|
||||
/**
|
||||
* Message family descriptor.
|
||||
*
|
||||
* Describes the structure of all message types with the same header and attributes.
|
||||
*/
|
||||
class MessageDescriptor {
|
||||
public:
|
||||
struct MessageDetails {
|
||||
std::string name;
|
||||
MessageGenre genre;
|
||||
};
|
||||
typedef std::map<nlmsgtype_t, MessageDetails> MessageDetailsMap;
|
||||
|
||||
public:
|
||||
virtual ~MessageDescriptor();
|
||||
|
||||
size_t getContentsSize() const;
|
||||
const MessageDetailsMap& getMessageDetailsMap() const;
|
||||
const AttributeMap& getAttributeMap() const;
|
||||
MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
|
||||
virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
|
||||
|
||||
/**
|
||||
* Message tracking for stateful protocols (such as NETLINK_GENERIC).
|
||||
*
|
||||
* \param hdr Message to track
|
||||
*/
|
||||
virtual void track(const Buffer<nlmsghdr> hdr);
|
||||
|
||||
static MessageDetails getMessageDetails(
|
||||
const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe,
|
||||
nlmsgtype_t msgtype);
|
||||
|
||||
protected:
|
||||
MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
|
||||
const AttributeMap&& attrTypes, size_t contentsSize);
|
||||
|
||||
private:
|
||||
const std::string mName;
|
||||
const size_t mContentsSize;
|
||||
const MessageDetailsMap mMessageDetails;
|
||||
const AttributeMap mAttributeMap;
|
||||
};
|
||||
|
||||
/**
|
||||
* Message definition template.
|
||||
*
|
||||
* A convenience initialization helper of a message descriptor.
|
||||
*/
|
||||
template <typename T>
|
||||
class MessageDefinition : public MessageDescriptor {
|
||||
public:
|
||||
MessageDefinition( //
|
||||
const std::string& name,
|
||||
const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
|
||||
const std::initializer_list<AttributeMap::value_type> attrTypes = {})
|
||||
: MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
|
||||
|
||||
void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {
|
||||
const auto& [ok, msg] = hdr.data<T>().getFirst();
|
||||
if (!ok) {
|
||||
ss << "{incomplete payload}";
|
||||
return;
|
||||
}
|
||||
|
||||
toStream(ss, msg);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void toStream(std::stringstream& ss, const T& data) const = 0;
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "NetlinkProtocol.h"
|
||||
|
||||
namespace android::nl::protocols {
|
||||
|
||||
NetlinkProtocol::NetlinkProtocol(int protocol, const std::string& name,
|
||||
const MessageDescriptorList&& messageDescrs)
|
||||
: mProtocol(protocol), mName(name), mMessageDescrs(toMap(messageDescrs, protocol)) {}
|
||||
|
||||
NetlinkProtocol::~NetlinkProtocol() {}
|
||||
|
||||
int NetlinkProtocol::getProtocol() const {
|
||||
return mProtocol;
|
||||
}
|
||||
|
||||
const std::string& NetlinkProtocol::getName() const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
const std::optional<std::reference_wrapper<MessageDescriptor>>
|
||||
NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
|
||||
if (mMessageDescrs.count(nlmsg_type) == 0) return std::nullopt;
|
||||
return *mMessageDescrs.find(nlmsg_type)->second;
|
||||
}
|
||||
|
||||
NetlinkProtocol::MessageDescriptorMap NetlinkProtocol::toMap(
|
||||
const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
|
||||
MessageDescriptorMap map;
|
||||
for (auto& descr : descrs) {
|
||||
for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
|
||||
map.emplace(mtype, descr);
|
||||
}
|
||||
}
|
||||
|
||||
const MessageDescriptorList baseDescriptors = {
|
||||
std::make_shared<base::Empty>(),
|
||||
std::make_shared<base::Error>(protocol),
|
||||
};
|
||||
|
||||
for (const auto& descr : baseDescriptors) {
|
||||
for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
|
||||
map.emplace(mtype, descr);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
} // namespace android::nl::protocols
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MessageDefinition.h"
|
||||
#include "common/Empty.h"
|
||||
#include "common/Error.h"
|
||||
|
||||
#include <libnl++/types.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace android::nl::protocols {
|
||||
|
||||
/**
|
||||
* Netlink-based protocol definition.
|
||||
*
|
||||
* Usually it's just an id/name and a list of supported messages.
|
||||
*/
|
||||
class NetlinkProtocol {
|
||||
public:
|
||||
virtual ~NetlinkProtocol();
|
||||
|
||||
int getProtocol() const;
|
||||
|
||||
const std::string& getName() const;
|
||||
|
||||
virtual const std::optional<std::reference_wrapper<MessageDescriptor>> getMessageDescriptor(
|
||||
nlmsgtype_t nlmsg_type);
|
||||
|
||||
protected:
|
||||
typedef std::vector<std::shared_ptr<MessageDescriptor>> MessageDescriptorList;
|
||||
|
||||
NetlinkProtocol(int protocol, const std::string& name,
|
||||
const MessageDescriptorList&& messageDescrs);
|
||||
|
||||
private:
|
||||
typedef std::map<nlmsgtype_t, std::shared_ptr<MessageDescriptor>> MessageDescriptorMap;
|
||||
|
||||
const int mProtocol;
|
||||
const std::string mName;
|
||||
const MessageDescriptorMap mMessageDescrs;
|
||||
|
||||
static MessageDescriptorMap toMap(const MessageDescriptorList& descrs, int protocol);
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols
|
||||
8
automotive/can/1.0/default/libnl++/protocols/README
Normal file
8
automotive/can/1.0/default/libnl++/protocols/README
Normal file
@@ -0,0 +1,8 @@
|
||||
This folder contains message definitions for various protocols based on Netlink.
|
||||
|
||||
The structure is as follows:
|
||||
protocols/*.(cpp|h) - base definition classes and protocol definition lookup
|
||||
protocols/common/ - common message types that apply to all protocols
|
||||
protocols/<proto>/<proto>.(cpp|h) - protocol definition (usually just a list of message types)
|
||||
protocols/<proto>/*.(cpp|h) - message definition that covers all message types with the same
|
||||
header (T type in MessageDefinition template) and attributes
|
||||
46
automotive/can/1.0/default/libnl++/protocols/all.cpp
Normal file
46
automotive/can/1.0/default/libnl++/protocols/all.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "all.h"
|
||||
|
||||
#include "generic/Generic.h"
|
||||
#include "route/Route.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace android::nl::protocols {
|
||||
|
||||
// This should be a map of unique_ptr, but it's not trivial to uniformly initialize such a map
|
||||
static std::map<int, std::shared_ptr<NetlinkProtocol>> toMap(
|
||||
std::initializer_list<std::shared_ptr<NetlinkProtocol>> l) {
|
||||
std::map<int, std::shared_ptr<NetlinkProtocol>> map;
|
||||
for (auto p : l) {
|
||||
map[p->getProtocol()] = p;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
} // namespace android::nl::protocols
|
||||
31
automotive/can/1.0/default/libnl++/protocols/all.h
Normal file
31
automotive/can/1.0/default/libnl++/protocols/all.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NetlinkProtocol.h"
|
||||
|
||||
namespace android::nl::protocols {
|
||||
|
||||
/**
|
||||
* Protocol definition lookup.
|
||||
*
|
||||
* \param protocol Protocol identifier from linux/netlink.h
|
||||
* \return Protocol definition or nullopt if it's not implemented
|
||||
*/
|
||||
std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol);
|
||||
|
||||
} // namespace android::nl::protocols
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Empty.h"
|
||||
|
||||
namespace android::nl::protocols::base {
|
||||
|
||||
// clang-format off
|
||||
Empty::Empty() : MessageDefinition<char>("nlmsg", {
|
||||
{NLMSG_NOOP, {"NOOP", MessageGenre::Unknown}},
|
||||
{NLMSG_DONE, {"DONE", MessageGenre::Unknown}},
|
||||
{NLMSG_OVERRUN, {"OVERRUN", MessageGenre::Unknown}},
|
||||
}) {}
|
||||
// clang-format on
|
||||
|
||||
void Empty::toStream(std::stringstream&, const char&) const {}
|
||||
|
||||
} // namespace android::nl::protocols::base
|
||||
32
automotive/can/1.0/default/libnl++/protocols/common/Empty.h
Normal file
32
automotive/can/1.0/default/libnl++/protocols/common/Empty.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../MessageDefinition.h"
|
||||
|
||||
#include <libnl++/printer.h>
|
||||
|
||||
namespace android::nl::protocols::base {
|
||||
|
||||
// no-payload (like NLMSG_NOOP) messages can't be defined with T=void, so let's use char
|
||||
class Empty : public MessageDefinition<char> {
|
||||
public:
|
||||
Empty();
|
||||
void toStream(std::stringstream&, const char&) const override;
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols::base
|
||||
191
automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
Normal file
191
automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Error.h"
|
||||
|
||||
#include "../MessageDefinition.h"
|
||||
|
||||
#include <libnl++/printer.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace android::nl::protocols::base {
|
||||
|
||||
using DataType = AttributeDefinition::DataType;
|
||||
|
||||
// clang-format off
|
||||
Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
|
||||
{NLMSG_ERROR, {"ERROR", MessageGenre::Ack}},
|
||||
}, {
|
||||
{NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
|
||||
{NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
|
||||
{NLMSGERR_ATTR_COOKIE, {"COOKIE", DataType::Raw}},
|
||||
}), mProtocol(protocol) {}
|
||||
// clang-format on
|
||||
|
||||
std::map<int, std::string> errnoNames{
|
||||
{EPERM, "EPERM"}, // Operation not permitted
|
||||
{ENOENT, "ENOENT"}, // No such file or directory
|
||||
{ESRCH, "ESRCH"}, // No such process
|
||||
{EINTR, "EINTR"}, // Interrupted system call
|
||||
{EIO, "EIO"}, // I/O error
|
||||
{ENXIO, "ENXIO"}, // No such device or address
|
||||
{E2BIG, "E2BIG"}, // Argument list too long
|
||||
{ENOEXEC, "ENOEXEC"}, // Exec format error
|
||||
{EBADF, "EBADF"}, // Bad file number
|
||||
{ECHILD, "ECHILD"}, // No child processes
|
||||
{EAGAIN, "EAGAIN"}, // Try again
|
||||
{ENOMEM, "ENOMEM"}, // Out of memory
|
||||
{EACCES, "EACCES"}, // Permission denied
|
||||
{EFAULT, "EFAULT"}, // Bad address
|
||||
{ENOTBLK, "ENOTBLK"}, // Block device required
|
||||
{EBUSY, "EBUSY"}, // Device or resource busy
|
||||
{EEXIST, "EEXIST"}, // File exists
|
||||
{EXDEV, "EXDEV"}, // Cross-device link
|
||||
{ENODEV, "ENODEV"}, // No such device
|
||||
{ENOTDIR, "ENOTDIR"}, // Not a directory
|
||||
{EISDIR, "EISDIR"}, // Is a directory
|
||||
{EINVAL, "EINVAL"}, // Invalid argument
|
||||
{ENFILE, "ENFILE"}, // File table overflow
|
||||
{EMFILE, "EMFILE"}, // Too many open files
|
||||
{ENOTTY, "ENOTTY"}, // Not a typewriter
|
||||
{ETXTBSY, "ETXTBSY"}, // Text file busy
|
||||
{EFBIG, "EFBIG"}, // File too large
|
||||
{ENOSPC, "ENOSPC"}, // No space left on device
|
||||
{ESPIPE, "ESPIPE"}, // Illegal seek
|
||||
{EROFS, "EROFS"}, // Read-only file system
|
||||
{EMLINK, "EMLINK"}, // Too many links
|
||||
{EPIPE, "EPIPE"}, // Broken pipe
|
||||
{EDOM, "EDOM"}, // Math argument out of domain of func
|
||||
{ERANGE, "ERANGE"}, // Math result not representable
|
||||
{EDEADLK, "EDEADLK"}, // Resource deadlock would occur
|
||||
{ENAMETOOLONG, "ENAMETOOLONG"}, // File name too long
|
||||
{ENOLCK, "ENOLCK"}, // No record locks available
|
||||
{ENOSYS, "ENOSYS"}, // Invalid system call number
|
||||
{ENOTEMPTY, "ENOTEMPTY"}, // Directory not empty
|
||||
{ELOOP, "ELOOP"}, // Too many symbolic links encountered
|
||||
{ENOMSG, "ENOMSG"}, // No message of desired type
|
||||
{EIDRM, "EIDRM"}, // Identifier removed
|
||||
{ECHRNG, "ECHRNG"}, // Channel number out of range
|
||||
{EL2NSYNC, "EL2NSYNC"}, // Level 2 not synchronized
|
||||
{EL3HLT, "EL3HLT"}, // Level 3 halted
|
||||
{EL3RST, "EL3RST"}, // Level 3 reset
|
||||
{ELNRNG, "ELNRNG"}, // Link number out of range
|
||||
{EUNATCH, "EUNATCH"}, // Protocol driver not attached
|
||||
{ENOCSI, "ENOCSI"}, // No CSI structure available
|
||||
{EL2HLT, "EL2HLT"}, // Level 2 halted
|
||||
{EBADE, "EBADE"}, // Invalid exchange
|
||||
{EBADR, "EBADR"}, // Invalid request descriptor
|
||||
{EXFULL, "EXFULL"}, // Exchange full
|
||||
{ENOANO, "ENOANO"}, // No anode
|
||||
{EBADRQC, "EBADRQC"}, // Invalid request code
|
||||
{EBADSLT, "EBADSLT"}, // Invalid slot
|
||||
{EBFONT, "EBFONT"}, // Bad font file format
|
||||
{ENOSTR, "ENOSTR"}, // Device not a stream
|
||||
{ENODATA, "ENODATA"}, // No data available
|
||||
{ETIME, "ETIME"}, // Timer expired
|
||||
{ENOSR, "ENOSR"}, // Out of streams resources
|
||||
{ENONET, "ENONET"}, // Machine is not on the network
|
||||
{ENOPKG, "ENOPKG"}, // Package not installed
|
||||
{EREMOTE, "EREMOTE"}, // Object is remote
|
||||
{ENOLINK, "ENOLINK"}, // Link has been severed
|
||||
{EADV, "EADV"}, // Advertise error
|
||||
{ESRMNT, "ESRMNT"}, // Srmount error
|
||||
{ECOMM, "ECOMM"}, // Communication error on send
|
||||
{EPROTO, "EPROTO"}, // Protocol error
|
||||
{EMULTIHOP, "EMULTIHOP"}, // Multihop attempted
|
||||
{EDOTDOT, "EDOTDOT"}, // RFS specific error
|
||||
{EBADMSG, "EBADMSG"}, // Not a data message
|
||||
{EOVERFLOW, "EOVERFLOW"}, // Value too large for defined data type
|
||||
{ENOTUNIQ, "ENOTUNIQ"}, // Name not unique on network
|
||||
{EBADFD, "EBADFD"}, // File descriptor in bad state
|
||||
{EREMCHG, "EREMCHG"}, // Remote address changed
|
||||
{ELIBACC, "ELIBACC"}, // Can not access a needed shared library
|
||||
{ELIBBAD, "ELIBBAD"}, // Accessing a corrupted shared library
|
||||
{ELIBSCN, "ELIBSCN"}, // .lib section in a.out corrupted
|
||||
{ELIBMAX, "ELIBMAX"}, // Attempting to link in too many shared libraries
|
||||
{ELIBEXEC, "ELIBEXEC"}, // Cannot exec a shared library directly
|
||||
{EILSEQ, "EILSEQ"}, // Illegal byte sequence
|
||||
{ERESTART, "ERESTART"}, // Interrupted system call should be restarted
|
||||
{ESTRPIPE, "ESTRPIPE"}, // Streams pipe error
|
||||
{EUSERS, "EUSERS"}, // Too many users
|
||||
{ENOTSOCK, "ENOTSOCK"}, // Socket operation on non-socket
|
||||
{EDESTADDRREQ, "EDESTADDRREQ"}, // Destination address required
|
||||
{EMSGSIZE, "EMSGSIZE"}, // Message too long
|
||||
{EPROTOTYPE, "EPROTOTYPE"}, // Protocol wrong type for socket
|
||||
{ENOPROTOOPT, "ENOPROTOOPT"}, // Protocol not available
|
||||
{EPROTONOSUPPORT, "EPROTONOSUPPORT"}, // Protocol not supported
|
||||
{ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"}, // Socket type not supported
|
||||
{EOPNOTSUPP, "EOPNOTSUPP"}, // Operation not supported on transport endpoint
|
||||
{EPFNOSUPPORT, "EPFNOSUPPORT"}, // Protocol family not supported
|
||||
{EAFNOSUPPORT, "EAFNOSUPPORT"}, // Address family not supported by protocol
|
||||
{EADDRINUSE, "EADDRINUSE"}, // Address already in use
|
||||
{EADDRNOTAVAIL, "EADDRNOTAVAIL"}, // Cannot assign requested address
|
||||
{ENETDOWN, "ENETDOWN"}, // Network is down
|
||||
{ENETUNREACH, "ENETUNREACH"}, // Network is unreachable
|
||||
{ENETRESET, "ENETRESET"}, // Network dropped connection because of reset
|
||||
{ECONNABORTED, "ECONNABORTED"}, // Software caused connection abort
|
||||
{ECONNRESET, "ECONNRESET"}, // Connection reset by peer
|
||||
{ENOBUFS, "ENOBUFS"}, // No buffer space available
|
||||
{EISCONN, "EISCONN"}, // Transport endpoint is already connected
|
||||
{ENOTCONN, "ENOTCONN"}, // Transport endpoint is not connected
|
||||
{ESHUTDOWN, "ESHUTDOWN"}, // Cannot send after transport endpoint shutdown
|
||||
{ETOOMANYREFS, "ETOOMANYREFS"}, // Too many references: cannot splice
|
||||
{ETIMEDOUT, "ETIMEDOUT"}, // Connection timed out
|
||||
{ECONNREFUSED, "ECONNREFUSED"}, // Connection refused
|
||||
{EHOSTDOWN, "EHOSTDOWN"}, // Host is down
|
||||
{EHOSTUNREACH, "EHOSTUNREACH"}, // No route to host
|
||||
{EALREADY, "EALREADY"}, // Operation already in progress
|
||||
{EINPROGRESS, "EINPROGRESS"}, // Operation now in progress
|
||||
{ESTALE, "ESTALE"}, // Stale file handle
|
||||
{EUCLEAN, "EUCLEAN"}, // Structure needs cleaning
|
||||
{ENOTNAM, "ENOTNAM"}, // Not a XENIX named type file
|
||||
{ENAVAIL, "ENAVAIL"}, // No XENIX semaphores available
|
||||
{EISNAM, "EISNAM"}, // Is a named type file
|
||||
{EREMOTEIO, "EREMOTEIO"}, // Remote I/O error
|
||||
{EDQUOT, "EDQUOT"}, // Quota exceeded
|
||||
{ENOMEDIUM, "ENOMEDIUM"}, // No medium found
|
||||
{EMEDIUMTYPE, "EMEDIUMTYPE"}, // Wrong medium type
|
||||
{ECANCELED, "ECANCELED"}, // Operation Canceled
|
||||
{ENOKEY, "ENOKEY"}, // Required key not available
|
||||
{EKEYEXPIRED, "EKEYEXPIRED"}, // Key has expired
|
||||
{EKEYREVOKED, "EKEYREVOKED"}, // Key has been revoked
|
||||
{EKEYREJECTED, "EKEYREJECTED"}, // Key was rejected by service
|
||||
{EOWNERDEAD, "EOWNERDEAD"}, // Owner died
|
||||
{ENOTRECOVERABLE, "ENOTRECOVERABLE"}, // State not recoverable
|
||||
{ERFKILL, "ERFKILL"}, // Operation not possible due to RF-kill
|
||||
{EHWPOISON, "EHWPOISON"}, // Memory page has hardware error
|
||||
|
||||
// Duplicates: EWOULDBLOCK (Operation would block), EDEADLOCK
|
||||
};
|
||||
|
||||
void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
|
||||
ss << "nlmsgerr{";
|
||||
if (data.error == 0) {
|
||||
ss << "ACK";
|
||||
} else {
|
||||
ss << "error=";
|
||||
const auto nameIt = errnoNames.find(-data.error);
|
||||
if (nameIt == errnoNames.end()) {
|
||||
ss << data.error;
|
||||
} else {
|
||||
ss << nameIt->second;
|
||||
}
|
||||
}
|
||||
ss << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
|
||||
}
|
||||
|
||||
} // namespace android::nl::protocols::base
|
||||
32
automotive/can/1.0/default/libnl++/protocols/common/Error.h
Normal file
32
automotive/can/1.0/default/libnl++/protocols/common/Error.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../MessageDefinition.h"
|
||||
|
||||
namespace android::nl::protocols::base {
|
||||
|
||||
class Error : public MessageDefinition<nlmsgerr> {
|
||||
public:
|
||||
Error(int protocol);
|
||||
void toStream(std::stringstream& ss, const nlmsgerr& data) const override;
|
||||
|
||||
private:
|
||||
const int mProtocol;
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols::base
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Ctrl.h"
|
||||
|
||||
#include "families/Nl80211.h"
|
||||
|
||||
#include <libnl++/Message.h>
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
using DataType = AttributeDefinition::DataType;
|
||||
using Flags = AttributeDefinition::Flags;
|
||||
|
||||
// clang-format off
|
||||
Ctrl::Ctrl(Generic::FamilyRegister& familyRegister)
|
||||
: GenericMessageBase(GENL_ID_CTRL, "ID_CTRL",
|
||||
{
|
||||
{CTRL_CMD_NEWFAMILY, "NEWFAMILY"},
|
||||
{CTRL_CMD_DELFAMILY, "DELFAMILY"},
|
||||
{CTRL_CMD_GETFAMILY, "GETFAMILY"},
|
||||
{CTRL_CMD_NEWOPS, "NEWOPS"},
|
||||
{CTRL_CMD_DELOPS, "DELOPS"},
|
||||
{CTRL_CMD_GETOPS, "GETOPS"},
|
||||
{CTRL_CMD_NEWMCAST_GRP, "NEWMCAST_GRP"},
|
||||
{CTRL_CMD_DELMCAST_GRP, "DELMCAST_GRP"},
|
||||
{CTRL_CMD_GETMCAST_GRP, "GETMCAST_GRP"},
|
||||
}, {
|
||||
{CTRL_ATTR_FAMILY_ID, {"FAMILY_ID", DataType::Uint}},
|
||||
{CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::StringNul}},
|
||||
{CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
|
||||
{CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
|
||||
{CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
|
||||
{CTRL_ATTR_OPS, {"OPS", DataType::Nested, AttributeMap{
|
||||
{std::nullopt, {"OP", DataType::Nested, AttributeMap{
|
||||
{CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
|
||||
{CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
|
||||
}}},
|
||||
}, Flags::Verbose}},
|
||||
{CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, AttributeMap{
|
||||
{std::nullopt, {"GRP", DataType::Nested, AttributeMap{
|
||||
{CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::StringNul}},
|
||||
{CTRL_ATTR_MCAST_GRP_ID, {"ID", DataType::Uint}},
|
||||
}}},
|
||||
}}},
|
||||
}), mFamilyRegister(familyRegister) {}
|
||||
// clang-format on
|
||||
|
||||
void Ctrl::track(const Buffer<nlmsghdr> hdr) {
|
||||
const auto msgMaybe = Message<genlmsghdr>::parse(hdr, {GENL_ID_CTRL});
|
||||
if (!msgMaybe.has_value()) return;
|
||||
const auto msg = *msgMaybe;
|
||||
|
||||
if (msg->cmd != CTRL_CMD_NEWFAMILY) return;
|
||||
const auto familyId = msg.attributes.get<uint16_t>(CTRL_ATTR_FAMILY_ID);
|
||||
const auto familyName = msg.attributes.get<std::string>(CTRL_ATTR_FAMILY_NAME);
|
||||
|
||||
/* For now, we support just a single family. But if you add more, please define proper
|
||||
* abstraction and not hardcode every name and class here.
|
||||
*/
|
||||
if (familyName == "nl80211") {
|
||||
mFamilyRegister[familyId] = std::make_shared<families::Nl80211>(familyId);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
34
automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
Normal file
34
automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Generic.h"
|
||||
#include "GenericMessageBase.h"
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
class Ctrl : public GenericMessageBase {
|
||||
public:
|
||||
Ctrl(Generic::FamilyRegister& familyRegister);
|
||||
|
||||
void track(const Buffer<nlmsghdr> hdr) override;
|
||||
|
||||
private:
|
||||
Generic::FamilyRegister& mFamilyRegister;
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libnl++/generic/FamilyTracker.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
namespace android::nl::generic {
|
||||
|
||||
bool FamilyTracker::track(const Buffer<nlmsghdr>& buffer) {
|
||||
const auto msgMaybe = nl::Message<genlmsghdr>::parse(buffer, {GENL_ID_CTRL});
|
||||
if (!msgMaybe.has_value()) return false;
|
||||
|
||||
const auto msg = *msgMaybe;
|
||||
if (msg->cmd != CTRL_CMD_NEWFAMILY) return true;
|
||||
|
||||
const auto familyName = msg.attributes.get<std::string>(CTRL_ATTR_FAMILY_NAME);
|
||||
const auto familyId = msg.attributes.get<uint16_t>(CTRL_ATTR_FAMILY_ID);
|
||||
|
||||
if (familyId < GENL_START_ALLOC) {
|
||||
LOG(WARNING) << "Invalid family ID: " << familyId;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (familyName == "nl80211") mNl80211FamilyId = familyId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Message<genlmsghdr>> FamilyTracker::parseNl80211(Buffer<nlmsghdr> msg) {
|
||||
if (track(msg)) return std::nullopt;
|
||||
if (!mNl80211FamilyId.has_value()) return std::nullopt;
|
||||
|
||||
return nl::Message<genlmsghdr>::parse(msg, {*mNl80211FamilyId});
|
||||
}
|
||||
|
||||
} // namespace android::nl::generic
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Generic.h"
|
||||
|
||||
#include "Ctrl.h"
|
||||
#include "Unknown.h"
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
Generic::Generic()
|
||||
: NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>(mFamilyRegister)}) {}
|
||||
|
||||
const std::optional<std::reference_wrapper<MessageDescriptor>> Generic::getMessageDescriptor(
|
||||
nlmsgtype_t nlmsg_type) {
|
||||
auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
|
||||
if (desc.has_value()) return desc;
|
||||
|
||||
auto it = mFamilyRegister.find(nlmsg_type);
|
||||
if (it != mFamilyRegister.end()) return *it->second;
|
||||
return *(mFamilyRegister[nlmsg_type] = std::make_shared<Unknown>(nlmsg_type));
|
||||
}
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../NetlinkProtocol.h"
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
/**
|
||||
* Definition of NETLINK_GENERIC protocol.
|
||||
*/
|
||||
class Generic : public NetlinkProtocol {
|
||||
public:
|
||||
typedef std::map<nlmsgtype_t, std::shared_ptr<MessageDescriptor>> FamilyRegister;
|
||||
|
||||
Generic();
|
||||
|
||||
const std::optional<std::reference_wrapper<MessageDescriptor>> getMessageDescriptor(
|
||||
nlmsgtype_t nlmsg_type);
|
||||
|
||||
private:
|
||||
FamilyRegister mFamilyRegister;
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "GenericMessageBase.h"
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
GenericMessageBase::GenericMessageBase(
|
||||
nlmsgtype_t msgtype, const std::string&& msgname,
|
||||
const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
|
||||
const std::initializer_list<AttributeMap::value_type> attrTypes)
|
||||
: MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::Unknown}}},
|
||||
attrTypes),
|
||||
mCommandNames(commandNames) {}
|
||||
|
||||
void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
|
||||
const auto commandNameIt = mCommandNames.find(data.cmd);
|
||||
const auto commandName = (commandNameIt == mCommandNames.end())
|
||||
? std::nullopt
|
||||
: std::optional<std::string>(commandNameIt->second);
|
||||
|
||||
if (commandName.has_value() && data.version == 1 && data.reserved == 0) {
|
||||
// short version
|
||||
ss << *commandName;
|
||||
return;
|
||||
}
|
||||
|
||||
ss << "genlmsghdr{";
|
||||
if (commandName.has_value()) {
|
||||
ss << "cmd=" << unsigned(data.cmd);
|
||||
} else {
|
||||
ss << "cmd=" << *commandName;
|
||||
}
|
||||
ss << ", version=" << unsigned(data.version);
|
||||
if (data.reserved != 0) ss << ", reserved=" << data.reserved;
|
||||
ss << "}";
|
||||
}
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../MessageDefinition.h"
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
class GenericMessageBase : public MessageDefinition<genlmsghdr> {
|
||||
public:
|
||||
typedef std::map<uint8_t, std::string> GenericCommandNameMap;
|
||||
|
||||
GenericMessageBase(
|
||||
nlmsgtype_t msgtype, const std::string&& msgname,
|
||||
const std::initializer_list<GenericCommandNameMap::value_type> commandNames = {},
|
||||
const std::initializer_list<AttributeMap::value_type> attrTypes = {});
|
||||
|
||||
void toStream(std::stringstream& ss, const genlmsghdr& data) const override;
|
||||
|
||||
private:
|
||||
const GenericCommandNameMap mCommandNames;
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Unknown.h"
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
Unknown::Unknown(nlmsgtype_t msgtype)
|
||||
: GenericMessageBase(msgtype, "Unknown(" + std::to_string(msgtype) + ")") {}
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GenericMessageBase.h"
|
||||
|
||||
namespace android::nl::protocols::generic {
|
||||
|
||||
class Unknown : public GenericMessageBase {
|
||||
public:
|
||||
Unknown(nlmsgtype_t msgtype);
|
||||
};
|
||||
|
||||
} // namespace android::nl::protocols::generic
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user