AIDL CAN HAL
CAN HAL: now HIDL-free with 100% of your daily value of AIDL.
Bug: 170405615
Test: atest CanControllerAidlTest
Test: manually test slcan and socketcan hardware
Change-Id: I06bbb1379f4385e89757722c0276009b54cc7255
diff --git a/automotive/can/aidl/Android.bp b/automotive/can/aidl/Android.bp
new file mode 100644
index 0000000..67333b9
--- /dev/null
+++ b/automotive/can/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.automotive.can",
+ vendor_available: true,
+ srcs: ["android/hardware/automotive/can/*.aidl"],
+ stability: "vintf",
+ host_supported: true,
+ backend: {
+ java: {
+ enabled: false,
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
new file mode 100644
index 0000000..0212e00
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@VintfStability
+parcelable BusConfig {
+ String name;
+ android.hardware.automotive.can.BusConfig.InterfaceId interfaceId;
+ int bitrate;
+ union InterfaceId {
+ android.hardware.automotive.can.VirtualInterface virtualif;
+ android.hardware.automotive.can.NativeInterface nativeif;
+ android.hardware.automotive.can.SlcanInterface slcan;
+ android.hardware.automotive.can.IndexedInterface indexed;
+ }
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
new file mode 100644
index 0000000..5d032f2
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@VintfStability
+interface ICanController {
+ android.hardware.automotive.can.InterfaceType[] getSupportedInterfaceTypes();
+ String getInterfaceName(in String busName);
+ String upBus(in android.hardware.automotive.can.BusConfig config);
+ void downBus(in String name);
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
new file mode 100644
index 0000000..1b00adf
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@VintfStability
+parcelable IndexedInterface {
+ byte index;
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
new file mode 100644
index 0000000..44865aa
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@Backing(type="byte") @VintfStability
+enum InterfaceType {
+ VIRTUAL = 0,
+ NATIVE = 1,
+ SLCAN = 2,
+ INDEXED = 3,
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
new file mode 100644
index 0000000..5d6c119
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@VintfStability
+parcelable NativeInterface {
+ android.hardware.automotive.can.NativeInterface.InterfaceId interfaceId;
+ union InterfaceId {
+ String ifname;
+ String[] serialno;
+ }
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
new file mode 100644
index 0000000..010792a
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@Backing(type="int") @VintfStability
+enum Result {
+ OK = 0,
+ UNKNOWN_ERROR = 1,
+ INVALID_STATE = 2,
+ NOT_SUPPORTED = 3,
+ BAD_INTERFACE_ID = 4,
+ BAD_BITRATE = 5,
+ BAD_BUS_NAME = 6,
+ INTERFACE_DOWN = 7,
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
new file mode 100644
index 0000000..af0c07d
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@VintfStability
+parcelable SlcanInterface {
+ android.hardware.automotive.can.SlcanInterface.InterfaceId interfaceId;
+ union InterfaceId {
+ String ttyname;
+ String[] serialno;
+ }
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
new file mode 100644
index 0000000..c870612
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.can;
+@VintfStability
+parcelable VirtualInterface {
+ String ifname;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl b/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl
new file mode 100644
index 0000000..4e1027b
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+import android.hardware.automotive.can.IndexedInterface;
+import android.hardware.automotive.can.NativeInterface;
+import android.hardware.automotive.can.SlcanInterface;
+import android.hardware.automotive.can.VirtualInterface;
+
+/**
+ * Configuration of the (physical or virtual) CAN bus.
+ *
+ * ISO TP and CAN FD support is dependent upon the hardware.
+ */
+@VintfStability
+parcelable BusConfig {
+ /**
+ * Name by which a given bus may be referenced.
+ *
+ * It must consist of only alphanumeric characters and underscore
+ * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
+ *
+ * This field is *not* meant to distinguish between hardware interfaces
+ * nor preselect parameters like bitrate.
+ *
+ * This field represents a more human-friendly name for a CAN bus:
+ * e.x. rather than /some/dev/can1234, "name" might be "BodyCAN" or "CCAN"
+ */
+ String name;
+
+ /**
+ * Hardware interface configuration.
+ *
+ * This union's discriminator has an equivalent enum {@see InterfaceType} to
+ * express compatibility via getSupportedInterfaceTypes().
+ */
+ union InterfaceId {
+ /** Virtual SocketCAN interface. */
+ VirtualInterface virtualif;
+
+ /** Native SocketCAN interface. */
+ NativeInterface nativeif;
+
+ /** Serial line CAN interface. */
+ SlcanInterface slcan;
+
+ /**
+ * Proprietary, device-specific interface.
+ *
+ * Non-SocketCAN interfaces should use this variant.
+ */
+ IndexedInterface indexed;
+ }
+
+ InterfaceId interfaceId;
+
+ /**
+ * Bit rate for CAN communication.
+ *
+ * Typical bit rates are: 100000, 125000, 250000, 500000.
+ *
+ * For {@see interfaceId#virtual} interfaces, this value is ignored.
+ */
+ int bitrate;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl b/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl
new file mode 100644
index 0000000..97c2674
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+import android.hardware.automotive.can.BusConfig;
+import android.hardware.automotive.can.InterfaceType;
+import android.hardware.automotive.can.Result;
+
+/**
+ * Represents a CAN controller that's capable of configuring CAN bus interfaces.
+ *
+ * The goal of this service is to configure and manage CAN interfaces.
+ *
+ * Providing an ICanController interface to configure CAN buses is optional.
+ * A system can elect to configure CAN buses manually if the hardware is
+ * dedicated to a specific application.
+ */
+@VintfStability
+interface ICanController {
+ /**
+ * Fetches the list of interface types supported by this HAL server.
+ *
+ * @return iftypes The list of supported interface types.
+ */
+ InterfaceType[] getSupportedInterfaceTypes();
+
+ /**
+ * Gets the interface name given the name of the bus. This will
+ *
+ * @param busName Name of the CAN bus who's interface name we would like
+ * (e.x. BCAN, CCAN, HS3, BodyCAN, ...)
+ * @return name of the socketcan network interface corresponding to busName
+ * (e.x. can0, vcan5, ...)
+ */
+ String getInterfaceName(in String busName);
+
+ /**
+ * Bring up a CAN bus.
+ *
+ * @param config Configuration for the CAN bus.
+ * @return name of iface if successful
+ */
+ String upBus(in BusConfig config);
+
+ /**
+ * Bring down a CAN bus.
+ *
+ * @param name Name of the bus (@see BusConfig#name} to bring down.
+ */
+ void downBus(in String name);
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl
new file mode 100644
index 0000000..13e223f
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable IndexedInterface {
+ /** Interface number, 0-based. */
+ byte index;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl b/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl
new file mode 100644
index 0000000..b13648a
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+/**
+ * Type of an interface, an equivalent to BusConfig::InterfaceId
+ * union discriminator. Defines a number of specific standard hardware
+ * families and a generic catch-all type of {@see INDEXED}.
+ */
+@VintfStability
+@Backing(type="byte")
+enum InterfaceType {
+ /** Virtual SocketCAN interface. */
+ VIRTUAL,
+
+ /** Native SocketCAN interface. */
+ NATIVE,
+
+ /** Serial line CAN interface. */
+ SLCAN,
+
+ /** Proprietary, device-specific interface. */
+ INDEXED,
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl
new file mode 100644
index 0000000..30c24c3
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable NativeInterface {
+ union InterfaceId {
+ /** Interface name, such as can0. */
+ String ifname;
+
+ /**
+ * Alternatively to providing {@see ifname}, one may provide a list of
+ * interface serial number suffixes. If there happens to be a device
+ * (like USB2CAN) with a matching serial number suffix, the HAL service
+ * will locate it.
+ *
+ * Client may utilize this in two ways: by matching against the
+ * entire serial number, or the last few characters (usually
+ * one). The former is better for small-scale test deployments
+ * (with just a handful of vehicles), the latter is good for
+ * larger scale (where a small suffix list may support large
+ * test fleet).
+ */
+ String[] serialno;
+ }
+
+ InterfaceId interfaceId;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/Result.aidl b/automotive/can/aidl/android/hardware/automotive/can/Result.aidl
new file mode 100644
index 0000000..cdd0066
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/Result.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+/**
+ * Possible error codes (or OK) for ICanController.
+ */
+@VintfStability
+@Backing(type="int")
+enum Result {
+ OK,
+
+ /**
+ * General error class, if others are not applicable.
+ */
+ UNKNOWN_ERROR,
+
+ /**
+ * Up request was called out of order (i.e. trying to up the interface
+ * twice).
+ */
+ INVALID_STATE,
+
+ /** Interface type is not supported. */
+ NOT_SUPPORTED,
+
+ /**
+ * Provided interface ID (index, name, device path) doesn't exist or there
+ * is no device with a given serial number.
+ */
+ BAD_INTERFACE_ID,
+
+ /** Provided bit rate is not supported by the hardware. */
+ BAD_BITRATE,
+
+ /**
+ * Provided bus name ({@see BusConfig#name}) has invalid format or doesn't exist.
+ */
+ BAD_BUS_NAME,
+
+ /**
+ * The interface for the bus you are trying to interact with is currently
+ * down. As opposed to INVALID_STATE, this serves to warn the caller
+ * _before_ they attempt an invalid operation.
+ */
+ INTERFACE_DOWN,
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl
new file mode 100644
index 0000000..4ed8583
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable SlcanInterface {
+ union InterfaceId {
+ /** Path to a device, such as /dev/ttyUSB0. */
+ String ttyname;
+
+ /**
+ * List of interface serial number suffixes.
+ * {@see Socketcan::serialno}
+ */
+ String[] serialno;
+ }
+
+ InterfaceId interfaceId;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl
new file mode 100644
index 0000000..7e1e5e1
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable VirtualInterface {
+ /**
+ * Interface name, such as vcan0. If the interface doesn't
+ * exist, HAL server must create it.
+ */
+ String ifname;
+}
diff --git a/automotive/can/aidl/default/Android.bp b/automotive/can/aidl/default/Android.bp
new file mode 100644
index 0000000..d44cb91
--- /dev/null
+++ b/automotive/can/aidl/default/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.can-service",
+ init_rc: ["android.hardware.automotive.can.rc"],
+ defaults: ["android.hardware.automotive.can@defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "CanBus.cpp",
+ "CanBusSlcan.cpp",
+ "CanBusNative.cpp",
+ "CanBusVirtual.cpp",
+ "CanController.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@libnetdevice",
+ "android.hardware.automotive@libc++fs",
+ "libnl++",
+ ],
+ vintf_fragments: ["android.hardware.automotive.can.xml"],
+}
diff --git a/automotive/can/aidl/default/CanBus.cpp b/automotive/can/aidl/default/CanBus.cpp
new file mode 100644
index 0000000..d1f9b78
--- /dev/null
+++ b/automotive/can/aidl/default/CanBus.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBus.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+CanBus::CanBus(std::string_view ifname) : mIfname(ifname) {}
+
+CanBus::~CanBus() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+ CHECK(!mIsUp) << "Interface is still up while being destroyed";
+}
+
+Result CanBus::preUp() {
+ return Result::OK;
+}
+
+bool CanBus::postDown() {
+ return true;
+}
+
+std::string CanBus::getIfaceName() {
+ return mIfname;
+}
+
+Result CanBus::up() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (mIsUp) {
+ LOG(WARNING) << "Interface is already up";
+ return Result::INVALID_STATE;
+ }
+
+ const auto preResult = preUp();
+ if (preResult != Result::OK) return preResult;
+
+ const auto isUp = ::android::netdevice::isUp(mIfname);
+ if (!isUp.has_value()) {
+ // preUp() should prepare the interface (either create or make sure it's there)
+ LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
+ return Result::BAD_INTERFACE_ID;
+ }
+
+ if (!*isUp && !::android::netdevice::up(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " up";
+ return Result::UNKNOWN_ERROR;
+ }
+ mDownAfterUse = !*isUp;
+
+ mIsUp = true;
+ return Result::OK;
+}
+
+Result CanBus::down() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (!mIsUp) {
+ LOG(WARNING) << "Interface is already down";
+ return Result::INVALID_STATE;
+ }
+ mIsUp = false;
+
+ Result success = Result::OK;
+
+ if (mDownAfterUse && !::android::netdevice::down(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " down";
+ // don't return yet, let's try to do best-effort cleanup
+ success = Result::UNKNOWN_ERROR;
+ }
+
+ if (!postDown()) success = Result::UNKNOWN_ERROR;
+
+ return success;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBus.h b/automotive/can/aidl/default/CanBus.h
new file mode 100644
index 0000000..abdbe51
--- /dev/null
+++ b/automotive/can/aidl/default/CanBus.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+#include <android-base/macros.h>
+#include <utils/Mutex.h>
+
+#include <atomic>
+#include <mutex>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBus {
+ public:
+ /**
+ * Some interface types (such as SLCAN) don't get an interface name until after being
+ * initialized, hence ifname is optional.
+ *
+ * You MUST ensure mIfname is initialized prior to the completion of preUp().
+ */
+ CanBus(std::string_view ifname = std::string_view{""});
+
+ virtual ~CanBus();
+
+ Result up();
+ Result down();
+ std::string getIfaceName();
+
+ protected:
+ /**
+ * Prepare the SocketCAN interface.
+ *
+ * After calling this method, mIfname network interface is available and ready to be brought up.
+ *
+ * \return true upon success and false upon failure
+ */
+ virtual Result preUp();
+
+ /**
+ * Cleanup after bringing the interface down.
+ *
+ * This is a counterpart to preUp().
+ *
+ * \return true upon success and false upon failure
+ */
+ virtual bool postDown();
+
+ /** Network interface name. */
+ std::string mIfname;
+
+ private:
+ /**
+ * Guard for up flag is required to be held for entire time when the interface is being used
+ * because we don't want the interface to be torn down while executing that operation.
+ */
+ std::mutex mIsUpGuard;
+ bool mIsUp GUARDED_BY(mIsUpGuard) = false;
+
+ bool mDownAfterUse;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusNative.cpp b/automotive/can/aidl/default/CanBusNative.cpp
new file mode 100644
index 0000000..8a7de99
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusNative.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace ::android;
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate)
+ : CanBus(ifname), mBitrate(bitrate) {}
+
+Result CanBusNative::preUp() {
+ if (!netdevice::exists(mIfname)) {
+ LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+ return Result::BAD_INTERFACE_ID;
+ }
+
+ if (mBitrate == 0) {
+ // interface is already up and we just want to register it
+ return Result::OK;
+ }
+
+ if (!netdevice::down(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ if (!netdevice::can::setBitrate(mIfname, mBitrate)) {
+ LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname;
+ return Result::BAD_BITRATE;
+ }
+
+ return Result::OK;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusNative.h b/automotive/can/aidl/default/CanBusNative.h
new file mode 100644
index 0000000..32846c7
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusNative.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusNative : public CanBus {
+ public:
+ CanBusNative(const std::string& ifname, uint32_t bitrate);
+
+ protected:
+ virtual Result preUp() override;
+
+ private:
+ const uint32_t mBitrate;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusSlcan.cpp b/automotive/can/aidl/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..6060419
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusSlcan.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusSlcan.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+
+#include <map>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace std::string_view_literals;
+using namespace ::android::base;
+
+namespace slcanprotocol {
+static constexpr std::string_view kOpenCommand = "O\r"sv;
+static constexpr std::string_view kCloseCommand = "C\r"sv;
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string_view> kBitrateCommands = {
+ {10000, "C\rS0\r"sv}, {20000, "C\rS1\r"sv}, {50000, "C\rS2\r"sv},
+ {100000, "C\rS3\r"sv}, {125000, "C\rS4\r"sv}, {250000, "C\rS5\r"sv},
+ {500000, "C\rS6\r"sv}, {800000, "C\rS7\r"sv}, {1000000, "C\rS8\r"sv}};
+} // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+ : CanBus(), mTtyPath(uartName), kBitrate(bitrate) {}
+
+/** helper function to update CanBusSlcan object's iface name */
+Result CanBusSlcan::updateIfaceName(unique_fd& uartFd) {
+ struct ifreq ifrequest = {};
+ /*
+ * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
+ * to this tty. This is important in the event we are trying to register a SLCAN based iface
+ * that has already been configured and brought up.
+ */
+ if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+ PLOG(ERROR) << "Failed to get the name of the created device";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ mIfname = ifrequest.ifr_name;
+ return Result::OK;
+}
+
+Result CanBusSlcan::preUp() {
+ // verify valid bitrate and translate to serial command format
+ std::optional<std::string_view> canBitrateCommand = std::nullopt;
+ if (kBitrate != 0) {
+ const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+ if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+ return Result::BAD_BITRATE;
+ }
+ canBitrateCommand = lookupIt->second;
+ }
+
+ /* Attempt to open the uart in r/w without blocking or becoming the
+ * controlling terminal */
+ mFd = unique_fd(open(mTtyPath.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC));
+ if (!mFd.ok()) {
+ PLOG(ERROR) << "SLCAN Failed to open " << mTtyPath;
+ return Result::BAD_INTERFACE_ID;
+ }
+
+ // If the device is already up, update the iface name in our CanBusSlcan object
+ if (kBitrate == 0) {
+ return updateIfaceName(mFd);
+ }
+
+ // blank terminal settings and pull them from the device
+ struct termios terminalSettings = {};
+ if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+ PLOG(ERROR) << "Failed to read attrs of" << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // change settings to raw mode
+ cfmakeraw(&terminalSettings);
+
+ // disable software flow control
+ terminalSettings.c_iflag &= ~IXOFF;
+ // enable hardware flow control
+ terminalSettings.c_cflag |= CRTSCTS;
+
+ struct serial_struct serialSettings;
+ // get serial settings
+ if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+ PLOG(ERROR) << "Failed to read serial settings from " << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+ // set low latency mode
+ serialSettings.flags |= ASYNC_LOW_LATENCY;
+ // apply serial settings
+ if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+ PLOG(ERROR) << "Failed to set low latency mode on " << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ /* TCSADRAIN applies settings after we finish writing the rest of our
+ * changes (as opposed to TCSANOW, which changes immediately) */
+ if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+ PLOG(ERROR) << "Failed to apply terminal settings to " << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // apply speed setting for CAN
+ if (!WriteStringToFd(*canBitrateCommand, mFd)) {
+ PLOG(ERROR) << "Failed to apply CAN bitrate";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // TODO(b/144775286): set open flag & support listen only
+ if (!WriteStringToFd(slcanprotocol::kOpenCommand, mFd)) {
+ PLOG(ERROR) << "Failed to set open flag";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // set line discipline to slcan
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+ PLOG(ERROR) << "Failed to set line discipline to slcan";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ return updateIfaceName(mFd);
+}
+
+bool CanBusSlcan::postDown() {
+ // reset the line discipline to TTY mode
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+ LOG(ERROR) << "Failed to reset line discipline!";
+ return false;
+ }
+
+ // issue the close command
+ if (!WriteStringToFd(slcanprotocol::kCloseCommand, mFd)) {
+ LOG(ERROR) << "Failed to close tty!";
+ return false;
+ }
+
+ // close our unique_fd
+ mFd.reset();
+
+ return true;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusSlcan.h b/automotive/can/aidl/default/CanBusSlcan.h
new file mode 100644
index 0000000..a1c908c
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusSlcan.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+#include <android-base/unique_fd.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusSlcan : public CanBus {
+ public:
+ CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+ protected:
+ virtual Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ Result updateIfaceName(::android::base::unique_fd& uartFd);
+
+ const std::string mTtyPath;
+ const uint32_t kBitrate;
+ ::android::base::unique_fd mFd;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusVirtual.cpp b/automotive/can/aidl/default/CanBusVirtual.cpp
new file mode 100644
index 0000000..28a1258
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusVirtual.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace ::android;
+
+CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
+
+Result CanBusVirtual::preUp() {
+ if (netdevice::exists(mIfname)) return Result::OK;
+
+ LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
+ mWasCreated = true;
+ if (!netdevice::add(mIfname, "vcan")) {
+ LOG(ERROR) << "Can't create vcan interface " << mIfname;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ return Result::OK;
+}
+
+bool CanBusVirtual::postDown() {
+ if (mWasCreated) {
+ mWasCreated = false;
+ if (!netdevice::del(mIfname)) {
+ LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusVirtual.h b/automotive/can/aidl/default/CanBusVirtual.h
new file mode 100644
index 0000000..9c5d35d
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusVirtual.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusVirtual : public CanBus {
+ public:
+ CanBusVirtual(const std::string& ifname);
+
+ protected:
+ virtual Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ bool mWasCreated = false;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanController.cpp b/automotive/can/aidl/default/CanController.cpp
new file mode 100644
index 0000000..e4b5306
--- /dev/null
+++ b/automotive/can/aidl/default/CanController.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include "CanBusNative.h"
+#include "CanBusSlcan.h"
+#include "CanBusVirtual.h"
+
+#include <android-base/format.h>
+#include <android-base/logging.h>
+
+#include <automotive/filesystem>
+#include <fstream>
+#include <regex>
+
+namespace aidl::android::hardware::automotive::can {
+
+namespace fs = ::android::hardware::automotive::filesystem;
+
+namespace fsErrors {
+static const std::error_code ok;
+static const std::error_code eperm(EPERM, std::generic_category());
+static const std::error_code enoent(ENOENT, std::generic_category());
+static const std::error_code eacces(EACCES, std::generic_category());
+} // namespace fsErrors
+
+/* In the /sys/devices tree, there are files called "serial", which contain the serial numbers
+ * for various devices. The exact location inside of this directory is dependent upon the
+ * hardware we are running on, so we have to start from /sys/devices and work our way down. */
+static const fs::path kDevPath("/sys/devices/");
+static const std::regex kTtyRe("^tty[A-Z]+[0-9]+$");
+static constexpr auto kOpts = ~(fs::directory_options::follow_directory_symlink |
+ fs::directory_options::skip_permission_denied);
+
+constexpr auto ok = &ndk::ScopedAStatus::ok;
+
+/**
+ * A helper object to associate the interface name and type of a USB to CAN adapter.
+ */
+struct UsbCanIface {
+ InterfaceType iftype;
+ std::string ifaceName;
+};
+
+static bool isValidName(const std::string& name) {
+ static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
+ return std::regex_match(name, nameRE);
+}
+
+/**
+ * Given a path, get the last element from it.
+ *
+ * \param itrPath - the path we want the last element of
+ * \return - the last element in the path (in string form).
+ */
+static std::string getLeaf(const fs::path& itrPath) {
+ /* end() returns an iterator one past the leaf of the path, so we've overshot
+ decrement (--) to go back one to the leaf
+ dereference and now we have our leaf. */
+ return *(--(itrPath.end()));
+}
+
+static ndk::ScopedAStatus resultToStatus(Result res, const std::string& msg = "") {
+ if (msg.empty()) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(static_cast<int>(res)));
+ }
+ return ndk::ScopedAStatus(
+ AStatus_fromServiceSpecificErrorWithMessage(static_cast<int>(res), msg.c_str()));
+}
+
+/**
+ * Given a UsbCanIface object, get the ifaceName given the serialPath.
+ *
+ * \param serialPath - Absolute path to a "serial" file for a given device in /sys.
+ * \return A populated UsbCanIface. On failure, nullopt is returned.
+ */
+static std::optional<UsbCanIface> getIfaceName(const fs::path& serialPath) {
+ std::error_code fsStatus;
+ // Since the path is to a file called "serial", we need to search its parent directory.
+ fs::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed to open " << serialPath.parent_path();
+ return std::nullopt;
+ }
+
+ for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+ fsItr.increment(fsStatus)) {
+ /* We want either a directory called "net" or a directory that looks like tty<something>, so
+ * skip files. */
+ bool isDir = fsItr->is_directory(fsStatus);
+ if (fsStatus != fsErrors::ok || !isDir) continue;
+
+ std::string currentDir = getLeaf(fsItr->path());
+ if (currentDir == "net") {
+ /* This device is a SocketCAN device. The iface name is the only directory under
+ * net/. Multiple directories under net/ is an error.*/
+ fs::directory_iterator netItr(fsItr->path(), kOpts, fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed to open " << fsItr->path() << " to get net name!";
+ return std::nullopt;
+ }
+
+ // The leaf of our path should be the interface name.
+ std::string netName = getLeaf(netItr->path());
+
+ // Check if there is more than one item in net/
+ netItr.increment(fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ // It's possible we have a valid net name, but this is most likely an error.
+ LOG(ERROR) << "Failed to verify " << fsItr->path() << " has valid net name!";
+ return std::nullopt;
+ }
+ if (netItr != fs::directory_iterator()) {
+ // There should never be more than one name under net/
+ LOG(ERROR) << "Found more than one net name in " << fsItr->path() << "!";
+ return std::nullopt;
+ }
+ return {{InterfaceType::NATIVE, netName}};
+ } else if (std::regex_match(currentDir, kTtyRe)) {
+ // This device is a USB serial device, and currentDir is the tty name.
+ return {{InterfaceType::SLCAN, "/dev/" + currentDir}};
+ }
+ }
+
+ // check if the loop above exited due to a c++fs error.
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed search filesystem: " << fsStatus;
+ }
+ return std::nullopt;
+}
+
+/**
+ * A helper function to read the serial number from a "serial" file in /sys/devices/
+ *
+ * \param serialnoPath - path to the file to read.
+ * \return the serial number, or nullopt on failure.
+ */
+static std::optional<std::string> readSerialNo(const std::string& serialnoPath) {
+ std::ifstream serialnoStream(serialnoPath);
+ std::string serialno;
+ if (!serialnoStream.good()) {
+ LOG(ERROR) << "Failed to read serial number from " << serialnoPath;
+ return std::nullopt;
+ }
+ std::getline(serialnoStream, serialno);
+ return serialno;
+}
+
+/**
+ * Searches for USB devices found in /sys/devices/, and attempts to find a device matching the
+ * provided list of serial numbers.
+ *
+ * \param configSerialnos - a list of serial number (suffixes) from the HAL config.
+ * \param iftype - the type of the interface to be located.
+ * \return a matching USB device. On failure, std::nullopt is returned.
+ */
+static std::optional<UsbCanIface> findUsbDevice(const std::vector<std::string>& configSerialnos) {
+ std::error_code fsStatus;
+ fs::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed to open " << kDevPath;
+ return std::nullopt;
+ }
+
+ for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+ fsItr.increment(fsStatus)) {
+ // We want to find a file called "serial", which is in a directory somewhere. Skip files.
+ bool isDir = fsItr->is_directory(fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed check if " << fsStatus;
+ return std::nullopt;
+ }
+ if (!isDir) continue;
+
+ auto serialnoPath = fsItr->path() / "serial";
+ bool isReg = fs::is_regular_file(serialnoPath, fsStatus);
+
+ /* Make sure we have permissions to this directory, ignore enoent, since the file
+ * "serial" may not exist, which is ok. */
+ if (fsStatus == fsErrors::eperm || fsStatus == fsErrors::eacces) {
+ /* This means we don't have access to this directory. If we recurse into it, this
+ * will cause the iterator to loose its state and we'll crash. */
+ fsItr.disable_recursion_pending();
+ continue;
+ }
+ if (fsStatus == fsErrors::enoent) continue;
+ if (fsStatus != fsErrors::ok) {
+ LOG(WARNING) << "An unexpected error occurred while checking for serialno: "
+ << fsStatus;
+ continue;
+ }
+ if (!isReg) continue;
+
+ // we found a serial number
+ auto serialno = readSerialNo(serialnoPath);
+ if (!serialno.has_value()) continue;
+
+ // see if the serial number exists in the config
+ for (auto&& cfgSn : configSerialnos) {
+ if (serialno->ends_with(std::string(cfgSn))) {
+ auto ifaceInfo = getIfaceName(serialnoPath);
+ if (!ifaceInfo.has_value()) break;
+ return ifaceInfo;
+ }
+ }
+ }
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Error searching filesystem: " << fsStatus;
+ return std::nullopt;
+ }
+ return std::nullopt;
+}
+
+ndk::ScopedAStatus CanController::getSupportedInterfaceTypes(
+ std::vector<InterfaceType>* supportedTypes) {
+ *supportedTypes = {InterfaceType::VIRTUAL, InterfaceType::NATIVE, InterfaceType::SLCAN};
+ return ok();
+}
+
+ndk::ScopedAStatus CanController::getInterfaceName(const std::string& busName,
+ std::string* ifaceName) {
+ *ifaceName = {};
+ if (mBusesByName.find(busName) == mBusesByName.end()) {
+ return resultToStatus(Result::BAD_BUS_NAME, fmt::format("{} doesn't exist", busName));
+ }
+ *ifaceName = std::string(mBusesByName[busName]->getIfaceName());
+ return ok();
+}
+
+ndk::ScopedAStatus CanController::upBus(const BusConfig& config, std::string* ifaceName) {
+ if (!isValidName(config.name)) {
+ LOG(ERROR) << "Bus name " << config.name << " is invalid";
+ return resultToStatus(Result::BAD_BUS_NAME,
+ fmt::format("{} is not a valid bus name", config.name));
+ } else if (mBusesByName.find(config.name) != mBusesByName.end()) {
+ LOG(ERROR) << "A bus named " << config.name << " already exists!";
+ return resultToStatus(Result::INVALID_STATE,
+ fmt::format("A bus named {} already exists", config.name));
+ }
+
+ if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::virtualif) {
+ auto& virtualif = config.interfaceId.get<BusConfig::InterfaceId::Tag::virtualif>();
+ mBusesByName[config.name] = std::make_unique<CanBusVirtual>(virtualif.ifname);
+ }
+
+ else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::nativeif) {
+ auto& nativeif = config.interfaceId.get<BusConfig::InterfaceId::Tag::nativeif>();
+ std::string ifaceName;
+ if (nativeif.interfaceId.getTag() == NativeInterface::InterfaceId::Tag::serialno) {
+ // Configure by serial number.
+ auto selectedDevice = findUsbDevice(
+ nativeif.interfaceId.get<NativeInterface::InterfaceId::Tag::serialno>());
+ // verify the returned device is the correct one
+ if (!selectedDevice.has_value() || selectedDevice->iftype != InterfaceType::NATIVE) {
+ return resultToStatus(
+ Result::BAD_INTERFACE_ID,
+ "Couldn't find a native socketcan device with the given serial number(s)");
+ }
+ ifaceName = selectedDevice->ifaceName;
+ } else {
+ // configure by iface name.
+ ifaceName = nativeif.interfaceId.get<NativeInterface::InterfaceId::Tag::ifname>();
+ }
+ mBusesByName[config.name] = std::make_unique<CanBusNative>(ifaceName, config.bitrate);
+ }
+
+ else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::slcan) {
+ auto& slcanif = config.interfaceId.get<BusConfig::InterfaceId::Tag::slcan>();
+ std::string ttyName;
+ if (slcanif.interfaceId.getTag() == SlcanInterface::InterfaceId::Tag::serialno) {
+ // Configure by serial number.
+ auto selectedDevice = findUsbDevice(
+ slcanif.interfaceId.get<SlcanInterface::InterfaceId::Tag::serialno>());
+ if (!selectedDevice.has_value() || selectedDevice->iftype != InterfaceType::SLCAN) {
+ return resultToStatus(
+ Result::BAD_INTERFACE_ID,
+ "Couldn't find a slcan device with the given serial number(s)");
+ }
+ ttyName = selectedDevice->ifaceName;
+ } else {
+ // Configure by tty name.
+ ttyName = slcanif.interfaceId.get<SlcanInterface::InterfaceId::Tag::ttyname>();
+ }
+ mBusesByName[config.name] = std::make_unique<CanBusSlcan>(ttyName, config.bitrate);
+ }
+
+ else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::indexed) {
+ return resultToStatus(Result::NOT_SUPPORTED,
+ "Indexed devices are not supported in this implementation");
+ } else {
+ // this shouldn't happen.
+ return resultToStatus(Result::UNKNOWN_ERROR, "Unknown interface id type");
+ }
+
+ Result result = mBusesByName[config.name]->up();
+ if (result != Result::OK) {
+ // the bus failed to come up, don't leave a broken entry in the map.
+ mBusesByName.erase(config.name);
+ return resultToStatus(result, fmt::format("CanBus::up failed for {}", config.name));
+ }
+
+ *ifaceName = mBusesByName[config.name]->getIfaceName();
+ return ok();
+}
+
+ndk::ScopedAStatus CanController::downBus(const std::string& busName) {
+ if (mBusesByName.find(busName) == mBusesByName.end()) {
+ return resultToStatus(
+ Result::UNKNOWN_ERROR,
+ fmt::format("Couldn't bring down {}, because it doesn't exist", busName));
+ }
+ Result result = mBusesByName[busName]->down();
+ if (result != Result::OK) {
+ return resultToStatus(result, fmt::format("Couldn't bring down {}!", busName));
+ }
+ mBusesByName.erase(busName);
+ return ok();
+}
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanController.h b/automotive/can/aidl/default/CanController.h
new file mode 100644
index 0000000..784906e
--- /dev/null
+++ b/automotive/can/aidl/default/CanController.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/can/BnCanController.h>
+
+#include "CanBus.h"
+
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+#include <map>
+#include <string>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanController : public BnCanController {
+ public:
+ ndk::ScopedAStatus getSupportedInterfaceTypes(
+ std::vector<InterfaceType>* supportedTypes) override;
+
+ ndk::ScopedAStatus getInterfaceName(const std::string& busName,
+ std::string* ifaceName) override;
+
+ ndk::ScopedAStatus upBus(const BusConfig& config, std::string* ifaceName) override;
+
+ ndk::ScopedAStatus downBus(const std::string& busName) override;
+
+ private:
+ std::map<std::string, std::unique_ptr<CanBus>> mBusesByName = {};
+};
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/android.hardware.automotive.can.rc b/automotive/can/aidl/default/android.hardware.automotive.can.rc
new file mode 100644
index 0000000..f843752
--- /dev/null
+++ b/automotive/can/aidl/default/android.hardware.automotive.can.rc
@@ -0,0 +1,5 @@
+service android.hardware.automotive.can /vendor/bin/hw/android.hardware.automotive.can-service
+ class hal
+ capabilities NET_ADMIN
+ user vehicle_network
+ group system inet
diff --git a/automotive/can/aidl/default/android.hardware.automotive.can.xml b/automotive/can/aidl/default/android.hardware.automotive.can.xml
new file mode 100644
index 0000000..873f333
--- /dev/null
+++ b/automotive/can/aidl/default/android.hardware.automotive.can.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.can</name>
+ <version>1</version>
+ <interface>
+ <name>ICanController</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/automotive/can/aidl/default/service.cpp b/automotive/can/aidl/default/service.cpp
new file mode 100644
index 0000000..eb45167
--- /dev/null
+++ b/automotive/can/aidl/default/service.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::automotive::can::CanController;
+
+extern "C" int main() {
+ base::SetDefaultTag("CanController");
+ base::SetMinimumLogSeverity(base::VERBOSE);
+
+ LOG(VERBOSE) << "Starting up...";
+ auto service = ndk::SharedRefBase::make<CanController>();
+ const auto instance = CanController::descriptor + "/default"s;
+ const auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance;
+ LOG(VERBOSE) << "Started successfully!";
+
+ ABinderProcess_joinThreadPool();
+ LOG(FATAL) << "CanController exited unexpectedly!";
+ return EXIT_FAILURE;
+}
+} // namespace android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/tools/configurator/Android.bp b/automotive/can/aidl/default/tools/configurator/Android.bp
new file mode 100644
index 0000000..1169894
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "canhalconfigurator-aidl",
+ init_rc: ["canhalconfigurator-aidl.rc"],
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "canhalconfigurator.cpp",
+ "canprototools.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libprotobuf-cpp-full",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can-V1-ndk",
+ "android.hardware.automotive.can-aidl-config-format",
+ ],
+}
diff --git a/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc b/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc
new file mode 100644
index 0000000..e1b4d35
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc
@@ -0,0 +1,3 @@
+service canhalconfigurator /system/bin/canhalconfigurator-aidl
+ class core
+ oneshot
diff --git a/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp b/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp
new file mode 100644
index 0000000..94e77b4
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "canbus_config.pb.h"
+#include "canprototools.h"
+
+#include <aidl/android/hardware/automotive/can/ICanController.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::automotive::can::ICanController;
+
+static constexpr std::string_view kDefaultConfigPath = "/etc/canbus_config.pb";
+
+/**
+ * Takes output from parsed protobuf config and uses it to configure the CAN HAL.
+ *
+ * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration.
+ * \return boolean status, true on success, false on failure.
+ */
+static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
+ for (auto const& bus : pb_cfg.buses()) {
+ if (bus.name().empty()) {
+ LOG(ERROR) << "Invalid config: Bus config must have a valid name field";
+ return false;
+ }
+
+ auto busCfgMaybe = config::fromPbBus(bus);
+ if (!busCfgMaybe.has_value()) {
+ return false;
+ }
+ auto busCfg = *busCfgMaybe;
+
+ const auto instance = ICanController::descriptor + "/default"s;
+ const auto service = ICanController::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+ if (service == nullptr) {
+ LOG(FATAL) << "Can't find CAN HAL! (has it started yet?)";
+ return false;
+ }
+
+ LOG(VERBOSE) << "Bringing up a " << busCfg.name << " @ " << busCfg.bitrate;
+
+ std::string ifaceName;
+ const auto status = service->upBus(busCfg, &ifaceName);
+ if (!status.isOk() && status.getExceptionCode() != EX_SERVICE_SPECIFIC) {
+ LOG(FATAL) << "Binder transaction failed!" << status.getStatus();
+ return false;
+ } else if (!status.isOk()) {
+ LOG(ERROR) << "upBus failed: " << config::resultStringFromStatus(status) << ": "
+ << status.getMessage();
+ continue;
+ }
+
+ LOG(INFO) << bus.name() << " has been successfully configured on " << ifaceName;
+ }
+ return true;
+}
+
+/**
+ * This kicks off the CAN HAL configuration process. This starts the following:
+ * 1. Reading the config file
+ * 2. Setting up CAN buses
+ * 3. Handling services
+ * \param filepath is a string specifying the absolute path of the config file
+ * \return boolean status, true on success, false on failure
+ */
+static bool configuratorStart(const std::string& filepath) {
+ base::SetDefaultTag("CanConfigurator");
+ auto pbCfg = config::parseConfigFile(filepath);
+ if (!pbCfg.has_value()) {
+ return false;
+ }
+ // process the rest of the config file data and configure the CAN buses.
+ if (!processPbCfg(*pbCfg)) {
+ return false;
+ }
+ LOG(INFO) << "CAN HAL has been configured!";
+ return true;
+}
+
+extern "C" int main(int argc, char* argv[]) {
+ std::string configFilepath = static_cast<std::string>(kDefaultConfigPath);
+
+ // allow for CLI specification of a config file.
+ if (argc == 2) {
+ configFilepath = argv[1];
+ } else if (argc > 2) {
+ std::cerr << "usage: " << argv[0] << " [optional config filepath]";
+ return 1;
+ }
+
+ if (!configuratorStart(configFilepath)) {
+ return 1;
+ }
+ return 0;
+}
+
+} // namespace android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.cpp b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
new file mode 100644
index 0000000..2aea315
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "canprototools.h"
+
+#include <aidl/android/hardware/automotive/can/IndexedInterface.h>
+#include <aidl/android/hardware/automotive/can/NativeInterface.h>
+#include <aidl/android/hardware/automotive/can/SlcanInterface.h>
+#include <aidl/android/hardware/automotive/can/VirtualInterface.h>
+
+#include <android-base/logging.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <fstream>
+
+namespace android::hardware::automotive::can::config {
+
+using ::aidl::android::hardware::automotive::can::BusConfig;
+using ::aidl::android::hardware::automotive::can::IndexedInterface;
+using ::aidl::android::hardware::automotive::can::InterfaceType;
+using ::aidl::android::hardware::automotive::can::NativeInterface;
+using ::aidl::android::hardware::automotive::can::Result;
+using ::aidl::android::hardware::automotive::can::SlcanInterface;
+using ::aidl::android::hardware::automotive::can::VirtualInterface;
+
+/**
+ * Helper function for parseConfigFile. readString is used to get the fist n characters (n) from an
+ * istream object (s) and return it as a string object.
+ *
+ * \param s istream of the file you intend to read.
+ * \param n streamsize object of the number of characters you'd like.
+ * \return optional string containing up to n characters from the stream(s) you provided.
+ */
+static std::optional<std::string> readString(std::istream& s, std::streamsize n) {
+ char buff[n];
+ auto got = s.read(buff, n).gcount();
+ if (!s.good() && !s.eof()) return std::nullopt;
+ return std::string(buff, 0, std::min(n, got));
+}
+
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+ std::ifstream cfg_stream(filepath);
+
+ // text headers that would be present in a plaintext proto config file.
+ static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
+ auto cfg_file_snippet = readString(cfg_stream, 10);
+
+ if (!cfg_file_snippet.has_value()) {
+ LOG(ERROR) << "Can't open " << filepath << " for reading";
+ return std::nullopt;
+ }
+ cfg_stream.seekg(0);
+
+ // check if any of the textHeaders are at the start of the config file.
+ bool text_format = false;
+ for (auto const& header : text_headers) {
+ if (cfg_file_snippet->compare(0, header.length(), header) == 0) {
+ text_format = true;
+ break;
+ }
+ }
+
+ CanBusConfig config;
+ if (text_format) {
+ google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
+ if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
+ LOG(ERROR) << "Failed to parse (text format) " << filepath;
+ return std::nullopt;
+ }
+ } else if (!config.ParseFromIstream(&cfg_stream)) {
+ LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+ return std::nullopt;
+ }
+ return config;
+}
+
+std::optional<BusConfig> fromPbBus(const Bus& pb_bus) {
+ BusConfig bus_cfg = {};
+ bus_cfg.name = pb_bus.name();
+
+ switch (pb_bus.iface_type_case()) {
+ case Bus::kNative: {
+ const std::string ifname = pb_bus.native().ifname();
+ const std::vector<std::string> serials = {pb_bus.native().serialno().begin(),
+ pb_bus.native().serialno().end()};
+ if (ifname.empty() == serials.empty()) {
+ LOG(ERROR) << "Invalid config: native type bus must have an iface name xor a "
+ << "serial number";
+ return std::nullopt;
+ }
+ bus_cfg.bitrate = pb_bus.bitrate();
+ NativeInterface nativeif = {};
+ if (!ifname.empty())
+ nativeif.interfaceId.set<NativeInterface::InterfaceId::Tag::ifname>(ifname);
+ if (!serials.empty())
+ nativeif.interfaceId.set<NativeInterface::InterfaceId::Tag::serialno>(serials);
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::nativeif>(nativeif);
+ break;
+ }
+ case Bus::kSlcan: {
+ const std::string ttyname = pb_bus.slcan().ttyname();
+ const std::vector<std::string> serials = {pb_bus.slcan().serialno().begin(),
+ pb_bus.slcan().serialno().end()};
+ if (ttyname.empty() == serials.empty()) {
+ LOG(ERROR) << "Invalid config: slcan type bus must have a tty name xor a serial "
+ << "number";
+ return std::nullopt;
+ }
+ bus_cfg.bitrate = pb_bus.bitrate();
+ SlcanInterface slcan = {};
+ if (!ttyname.empty())
+ slcan.interfaceId.set<SlcanInterface::InterfaceId::Tag::ttyname>(ttyname);
+ if (!serials.empty())
+ slcan.interfaceId.set<SlcanInterface::InterfaceId::Tag::serialno>(serials);
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::slcan>(slcan);
+ break;
+ }
+ case Bus::kVirtual: {
+ // Theoretically, we could just create the next available vcan iface.
+ const std::string ifname = pb_bus.virtual_().ifname();
+ if (ifname.empty()) {
+ LOG(ERROR) << "Invalid config: native type bus must have an iface name";
+ return std::nullopt;
+ }
+ VirtualInterface virtualif = {};
+ virtualif.ifname = ifname;
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::virtualif>(virtualif);
+ break;
+ }
+ case Bus::kIndexed: {
+ const uint8_t index = pb_bus.indexed().index();
+ if (index > UINT8_MAX) {
+ LOG(ERROR) << "Interface index out of range: " << index;
+ return std::nullopt;
+ }
+ IndexedInterface indexedif = {};
+ indexedif.index = index;
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::indexed>(indexedif);
+ break;
+ }
+ default:
+ LOG(ERROR) << "Invalid config: bad interface type for " << bus_cfg.name;
+ return std::nullopt;
+ }
+ return bus_cfg;
+}
+
+std::optional<InterfaceType> getHalIftype(const Bus& pb_bus) {
+ switch (pb_bus.iface_type_case()) {
+ case Bus::kNative:
+ return InterfaceType::NATIVE;
+ case Bus::kSlcan:
+ return InterfaceType::SLCAN;
+ case Bus::kVirtual:
+ return InterfaceType::VIRTUAL;
+ case Bus::kIndexed:
+ return InterfaceType::INDEXED;
+ default:
+ return std::nullopt;
+ }
+}
+
+std::string resultStringFromStatus(const ndk::ScopedAStatus& status) {
+ const auto res = static_cast<Result>(status.getServiceSpecificError());
+ switch (res) {
+ case Result::OK:
+ return "OK";
+ case Result::UNKNOWN_ERROR:
+ return "UNKNOWN_ERROR";
+ case Result::INVALID_STATE:
+ return "INVALID_STATE";
+ case Result::NOT_SUPPORTED:
+ return "NOT_SUPPORTED";
+ case Result::BAD_INTERFACE_ID:
+ return "BAD_INTERFACE_ID";
+ case Result::BAD_BITRATE:
+ return "BAD_BITRATE";
+ case Result::BAD_BUS_NAME:
+ return "BAD_BUS_NAME";
+ case Result::INTERFACE_DOWN:
+ return "INTERFACE_DOWN";
+ default:
+ return "Invalid Result!";
+ }
+}
+
+} // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.h b/automotive/can/aidl/default/tools/configurator/canprototools.h
new file mode 100644
index 0000000..377ee7f
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "canbus_config.pb.h"
+
+#include <aidl/android/hardware/automotive/can/BusConfig.h>
+#include <aidl/android/hardware/automotive/can/InterfaceType.h>
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+namespace android::hardware::automotive::can::config {
+
+/**
+ * This reads the protobuf config file into a protobuf object. Both text based protobuf files as
+ * well as binary format protobuf files are supported.
+ *
+ * \param filepath string containing the name of the config file to read.
+ * \return a CanBusConfig protobuf object constructed from the config file.
+ */
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath);
+
+/**
+ * Converts protobuf format single-bus config object to a HAL bus config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return a converted HAL bus config object.
+ */
+std::optional<::aidl::android::hardware::automotive::can::BusConfig> fromPbBus(const Bus& pb_bus);
+
+/**
+ * Get the CAN HAL interface type specified by a given protobuf config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return the CAN HAL interface type.
+ */
+std::optional<::aidl::android::hardware::automotive::can::InterfaceType> getHalIftype(
+ const Bus& pb_bus);
+
+std::string resultStringFromStatus(const ndk::ScopedAStatus& status);
+
+} // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/aidl/default/tools/configurator/proto/Android.bp b/automotive/can/aidl/default/tools/configurator/proto/Android.bp
new file mode 100644
index 0000000..da1b37c
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/proto/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // 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: "android.hardware.automotive.can-aidl-config-format",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+ strip: {
+ keep_symbols: true,
+ },
+ srcs: ["canbus_config.proto"],
+}
diff --git a/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto b/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto
new file mode 100644
index 0000000..b03b035
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.can.config;
+
+message IfaceNative {
+ string ifname = 1;
+ repeated string serialno = 2;
+};
+
+message IfaceSlcan {
+ string ttyname = 1;
+ repeated string serialno = 2;
+};
+
+message IfaceVirtual {
+ string ifname = 1;
+};
+
+message IfaceIndexed {
+ uint32 index = 1;
+};
+
+message Bus {
+ string name = 1; // this is the name presented in the HAL
+ oneof iface_type {
+ IfaceNative native = 2;
+ IfaceSlcan slcan = 3;
+ IfaceVirtual virtual = 4;
+ IfaceIndexed indexed = 5;
+ }
+ uint32 bitrate = 6;
+};
+
+message CanBusConfig {
+ repeated Bus buses = 1;
+};
diff --git a/automotive/can/aidl/vts/functional/Android.bp b/automotive/can/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..b816a49
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalCanControllerV1_0Test",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.automotive.can@defaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ cpp_std: "experimental",
+ srcs: [
+ "CanControllerAidlTest.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can-V1-ndk",
+ "android.hardware.automotive.can@libnetdevice",
+ "libnl++",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp b/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp
new file mode 100644
index 0000000..c2b2879
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/can/BusConfig.h>
+#include <aidl/android/hardware/automotive/can/ICanController.h>
+#include <aidl/android/hardware/automotive/can/Result.h>
+#include <aidl/android/hardware/automotive/can/VirtualInterface.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <libnetdevice/libnetdevice.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+#include <libnl++/printer.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <chrono>
+#include <thread>
+
+using aidl::android::hardware::automotive::can::BusConfig;
+using aidl::android::hardware::automotive::can::ICanController;
+using aidl::android::hardware::automotive::can::VirtualInterface;
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+class CanControllerAidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ android::base::SetDefaultTag("CAN_HAL_VTS");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ const auto instance = ICanController::descriptor + "/default"s;
+ mCanControllerService = ICanController::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+
+ ASSERT_NE(mCanControllerService, nullptr);
+ }
+ virtual void TearDown() override {}
+
+ static bool mTestCaseInitialized;
+ std::shared_ptr<ICanController> mCanControllerService;
+};
+
+// we can't test a real bus, since we can't make any assumptions about hardware
+// this checks upBus, getInterfaceName, and downBus
+TEST_P(CanControllerAidlTest, ToggleBus) {
+ const std::string_view canIface = "vcan50";
+ const std::string busName = "VTS_CAN";
+
+ std::string upBusReturn; // should be vcan50
+ BusConfig config = {};
+ VirtualInterface iface = {};
+ iface.ifname = canIface;
+ config.interfaceId.set<BusConfig::InterfaceId::Tag::virtualif>(iface);
+ config.name = busName;
+ auto aidlStatus = mCanControllerService->upBus(config, &upBusReturn);
+ ASSERT_TRUE(aidlStatus.isOk());
+ EXPECT_EQ(upBusReturn, canIface);
+
+ std::string ifaceName;
+ aidlStatus = mCanControllerService->getInterfaceName(busName, &ifaceName);
+ ASSERT_TRUE(aidlStatus.isOk());
+ EXPECT_EQ(ifaceName, canIface);
+
+ aidlStatus = mCanControllerService->downBus(busName);
+ ASSERT_TRUE(aidlStatus.isOk());
+}
+
+TEST_P(CanControllerAidlTest, GetSupported) {
+ LOG(VERBOSE) << "Get the supported iface types";
+ std::vector<::aidl::android::hardware::automotive::can::InterfaceType> supportedTypes;
+ auto aidlStatus = mCanControllerService->getSupportedInterfaceTypes(&supportedTypes);
+ ASSERT_TRUE(aidlStatus.isOk());
+ EXPECT_FALSE(supportedTypes.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, CanControllerAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ICanController::descriptor)),
+ android::PrintInstanceNameToString);
diff --git a/automotive/can/aidl/vts/functional/OWNERS b/automotive/can/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..85257a3
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 533426
[email protected]
[email protected]
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index dc87c63..ebc3dff 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -68,6 +68,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.automotive.can</name>
+ <version>1</version>
+ <interface>
+ <name>ICanController</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.automotive.can</name>
<version>1.0</version>