Merge Android 12
Bug: 202323961 Merged-In: I76b505672b7c78b03a9c79df6473212ea5c65072 Change-Id: I262cbcc8dcfb0cad2b8e2f393c95829afe6b3827
This commit is contained in:
commit
ac9783cd54
1030 changed files with 60471 additions and 4511 deletions
|
@ -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
Loading…
Reference in a new issue