diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..699a469 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +.vscode +libs/* diff --git a/README.md b/README.md index f1411e4..a5aee41 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Whether you are an OEM company or a developer customizing the Android Open Sourc The Android Software Development Kit (SDK) is a collection of libraries and tools that enables and makes it easier to develop Android applications. SDK Add-ons allow third-party actors to extend the Android SDK to add interfaces to their features without changing the Android SDK. According to the Android Compatibility Definition Document (CDD), OEMs are not allowed to change the Android public APIs - namely those in the protected namespaces: `java.*`, `javax.*`, `sun.*`, `android.*`, `com.android.*`. Therefore, by using add-ons, OEMs can add libraries in their namespaces, providing functionalities that can be exported without infringing the CDD. Having to build only the add-on is also a great advantage that might save a lot of development time. -In this post, we will build an SDK Add-on containing an example service - for which we will cover all the necessary config files. We will also learn how to connect an application to our example service using the add-on. Here, we are assuming you already have access to the Android source code and that you can build and deploy these changes. The code and configuration files were made with Android 10 (API level 30) in mind but they can be easily modifiable to work with other versions. +In this project, we will build an SDK Add-on containing example services - for which we will cover all the necessary config files. We will also learn how to connect an application to our example services using the add-on. Here, we are assuming you already have access to the Android source code and that you can build and deploy these changes. The code and configuration files were made with Android 14 (API level 34) in mind but they can be easily modifiable to work with other versions. ## Setting up the AOSP source tree @@ -19,14 +19,20 @@ repo sync ### The content of this repository -This repository contains the code to build an emulator image containing the **hello-world-service**, the SDK add-on containing the **hello-world-service** service libraries that apps that use the **hello-world-service** will use on theirs build process, and a sample app that will use the SDK add-on. The summary of the code follows: +This repository contains the code to build an emulator image containing some services, the SDK add-on with stubs that allow apps to communicate with these services, and a sample app that will use the SDK add-on. First, let's see how the **hello-world-service** example is structured: * `device/profusion/profusion_sdk_addon`: contains the configuration and manifest files for the SDK add-on. The `profusion_sdk_addon.mk` includes the **helloworld** product as part of this add-on; * `pacakges/services/profusion/hello-world-service`: contains the service itself, that will be run in the emulator and serve the applications. The service will be part of the framework; * `target`: contains files related to the emulator that will be created. Instead of creating a new device, we just modified the `sdk_car_x86_64.mk` and `car_generic_system.mk` to include our add-on. -We supply a shell script `add_to_aosp.sh` to automatically copy all code to the correct place in the AOSP source tree. Pass to the script the path to where the AOSP repo is: +We supply two different shell scripts. The first one, `fetch_someip_libs.sh`, is responsible for cloning all the necessary libraries to work with SOME/IP and CommonAPI. You only need to run this script once. It's also necessary to generate the files of some_ip_hal example to compile the project. So clone the libraries with the script below and run the commands described at [Generating CommonAPI Files](doc/SOME-IP-HAL.md#generating-commonapi-files) (Don't worry about understanding the whole context of SOME/IP right now, just run the commands in this topic for now). + +```bash +./fetch_someip_libs.sh +``` + +The second one called `add_to_aosp.sh` will automatically copy all code to the correct place in the AOSP source tree. Run these two scripts one after the other, changing `/pathTo/aosp` for the path to your AOSP source tree: ```bash ./add_to_aosp.sh /pathTo/aosp @@ -34,7 +40,9 @@ We supply a shell script `add_to_aosp.sh` to automatically copy all code to the If you use VSCode, you can use [Run on Save](https://marketplace.visualstudio.com/items?itemName=emeraldwalk.RunOnSave) to automatically update the files with this script on save. +#### Sample HAL implementation +This repository also contains an example of how to develop a HAL and use it through the SDK-Addon. First, focus on how the **hello-world-service** example is described here. Then, take a look at the [HAL Documentation](doc/HAL.md).And then, if you are comfortable going further, take a look at the [HAL using SOME/IP](doc/SOME-IP-HAL.md), which is a more complex example involving a HAL that uses SOME/IP to communicate with a provider service. ## Hello World System Service @@ -144,6 +152,8 @@ Should contain commands that the blueprint cannot support. Since Android 11, the If you already have a service, then this is the interesting part: You need a `.mk` file that defines the name and properties of your SDK Add-on, and several other files that define miscellaneous properties such as the API level being used, the revision version, and the libraries contained in the add-on. During the Android build, these files are bundled into a `.zip` containing the add-on to be distributed. In the next sections, I will go into further detail into each of the included files. +**PS**: Here, we will only show the files with the HelloWorld service. But if you look at these files in the source itself, you will see how to add more Services/Managers to the add-on. + ##### `profusion_sdk_addon.mk` ```make @@ -264,10 +274,11 @@ The SDK Add-on is all set. Now we only have to build it. Notice, again, that I'm . build/envsetup.sh export TARGET=profusion_sdk_addon lunch sdk_car_x86_64-trunk_staging-eng +m profusion.hardware.dummy_car_info_hal-update-api # to freeze AIDL interfaces from HAL example make sdk_addon ``` -When the compilation succeeds, you will see two `.zip` files at `out/host/linux-x86/sdk_addon`. `profusion_sdk_addon-linux.zip` will contain the addon itself, which will be used to develop and compile our app. `profusion_sdk_addon-linux-img.zip` will contain a set of files to run the emulator outside the AOSP file tree. +When the compilation succeeds, you will see two `.zip` files at `out/host/linux-x86/sdk_addon`. `profusion_sdk_addon-linux.zip` will contain the addon itself, which will be used to develop and compile our app. `profusion_sdk_addon-linux-img.zip` will supposedly contain the files to run an emulator. We will see how to use it later. ### Building Android @@ -279,6 +290,8 @@ lunch sdk_car_x86_64-trunk_staging-eng m ``` +**Tip**: Sometimes, you may want to build only one specific module (the hello-world-service, for example) to test small changes. To do this, run `mmm packages/hello-world-service`. + ## Adding the SDK Add-on to Android Studio Check the environment variable that points to Android's Sdk root. @@ -415,20 +428,27 @@ emulator ### Outside the AOSP tree -If you use a remote server to build your addon (It could be a good idea. Building the AOSP right now could be a really really hard job for some hardware) you will probably want to extract the emulator to your local machine. Actually, that's very easy and you already have all you need. +If you use a remote server to build your addon (It could be a good idea. Building the AOSP right now could be a really really hard job for some hardware) you will probably want to extract the emulator to your local machine. The `profusion_sdk_addon-linux-img.zip` generated by the build process should contain the emulator image, but I had trouble running it. So, we will use another make command to generate the image: -Go to your Android Studio and create an emulator using the *Device Manager* tool. Since we builded to a Automotive TARGET, select an hardware under the _Automotive_ category as well. For the _system image_, select (or download first if you don't have it yet) the API 34 image. +```bash +make emu_img_zip +``` -Before launching the emulator, extract the content of `profusion_sdk_addon-linux-img.zip` to the API 34 image folder: +This command will pack all the necessary files to create an emulator in a file called `sdk-repo-linux-system-images.zip` under the `out/target/product/emulator_car64_x86_64` folder. Copy this file to your local machine. This usually can be done with a `scp` command, like: ```bash -unzip out/host/linux-x86/sdk_addon/profusion_sdk_addon-linux-img.zip -d $ANDROID_SDK_ROOT/system-images/android-34-ext9/android-automotive +scp @:/out/target/product/emulator_car64_x86_64/sdk-repo-linux-system-images.zip ``` ---- -Note: If you choose to build a different TARGET like `aosp_x86_64` or another, you will need to extract the content to a different path and the `profusion_sdk_addon-linux-img.zip` could not work as expected. In that case, you could use `make emu_img_zip` to generate a similar `sdk-repo-linux-system-images.zip` under `$PRODUCT_OUT` folder. +Go to your Android Studio and create an emulator using the *Device Manager* tool. Since we builded to a Automotive TARGET, select an hardware under the _Automotive_ category as well. For the _system image_, select (or download first if you don't have it yet) the API 34 image. + +Before launching the emulator, extract the content of `sdk-repo-linux-system-images.zip` to the API 34 image folder: + +```bash +unzip pathTo/sdk-repo-linux-system-images.zip -d $ANDROID_SDK_ROOT/system-images/android-34-ext9/android-automotive +``` ---- +And that's it! You can now run the emulator and test the features. ### Build and install the App @@ -458,3 +478,8 @@ adb shell ``` ![Android emulator running the helloworld app and helloword service](assets/running_app.png "Helloworld App") + +### Next steps + +Now you know how to build an SDK Add-on with a simple hello world service example. You can use this to develop your service! +Also, I **highly recommend** you read the [HAL Documentation](doc/HAL.md). There, you will find and robust example of how to develop a Hardware Abstraction Layer service and use it through the SDK Add-on using Managers, removing the Service binding responsibility from the application. diff --git a/add_to_aosp.sh b/add_to_aosp.sh index f5cb4e0..fdfd07e 100755 --- a/add_to_aosp.sh +++ b/add_to_aosp.sh @@ -18,9 +18,15 @@ rsync -a --inplace "$GIT_ROOT"/target/userdata.img "$AOSP"/device/generic/goldfi echo "Copying profusion sdk addon to device" rsync -a --inplace "$GIT_ROOT"/device "$AOSP" -echo "Copying helloworld service to the framework" +echo "Copying services to the framework" rsync -a --inplace "$GIT_ROOT"/packages "$AOSP" +echo "Copying HALs to the hardware" +rsync -a --inplace "$GIT_ROOT"/hardware "$AOSP" + mkdir -p "$AOSP"/out/target/product/emulator_car64_x86_64/data +echo "Copying COMMONAPI libs" +rsync -a --exclude '.git' "$GIT_ROOT"/libs/ "$AOSP"/external + date '+%Y/%m/%d %H:%M:%S' diff --git a/app/HelloWorldApp/app/src/main/AndroidManifest.xml b/app/HelloWorldApp/app/src/main/AndroidManifest.xml index 0e88b34..fd374c1 100644 --- a/app/HelloWorldApp/app/src/main/AndroidManifest.xml +++ b/app/HelloWorldApp/app/src/main/AndroidManifest.xml @@ -12,6 +12,8 @@ android:theme="@style/Theme.HelloWorldApp"> + MainContent( modifier = Modifier.padding(innerPadding), - onButtonClick = { + onHelloWorldButtonClick = { helloWorldService?.printHelloWorld() - } + }, + onCarInfoButtonClick = { + carInfoState = try { + dummyCarInfoManager!!.carInfo + } catch (e: Exception) { + "Error: ${e.message}" + } + }, + carInfoState = carInfoState, ) } } } } + override fun onDestroy() { + super.onDestroy() + dummyCarInfoManager?.unbindService(); + } + override fun onStart() { super.onStart() + dummyCarInfoManager = DummyCarInfoManager(this) val intent = Intent() intent.component = ComponentName(HELLO_WORLD_SERVICE_PACKAGE, HELLO_WORLD_SERVICE) try { this.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) } catch (e: Exception) { - Log.e(TAG, "Unable to bind HelloWorldService"); + Log.e(TAG, "Unable to bind"); e.printStackTrace() } } @@ -74,19 +97,37 @@ class MainActivity : ComponentActivity() { } @Composable -fun MainContent(modifier: Modifier = Modifier, onButtonClick: () -> Unit) { +fun MainContent( + modifier: Modifier = Modifier, + onHelloWorldButtonClick: () -> Unit, + onCarInfoButtonClick: () -> Unit, + carInfoState: String, +) { Column( modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Button( - onClick = onButtonClick, + onClick = onHelloWorldButtonClick, ) { Text( stringResource(R.string.helloWorldButtonText), fontSize = 32.sp, ) } + Button( + modifier = Modifier.padding(vertical = 16.dp), + onClick = onCarInfoButtonClick, + ) { + Text( + stringResource(R.string.carInfoButtonText), + fontSize = 32.sp, + ) + } + Text( + text = carInfoState, + fontSize = 32.sp, + ) } -} \ No newline at end of file +} diff --git a/app/HelloWorldApp/app/src/main/res/values/strings.xml b/app/HelloWorldApp/app/src/main/res/values/strings.xml index ceb0b2f..acd45be 100644 --- a/app/HelloWorldApp/app/src/main/res/values/strings.xml +++ b/app/HelloWorldApp/app/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ HelloWorldApp Tap to call HelloWorldService! + Tap to call DummyCarInfoManager! diff --git a/assets/playground_service_log.png b/assets/playground_service_log.png new file mode 100644 index 0000000..5a1920e Binary files /dev/null and b/assets/playground_service_log.png differ diff --git a/assets/running_app_hal.gif b/assets/running_app_hal.gif new file mode 100644 index 0000000..191640e Binary files /dev/null and b/assets/running_app_hal.gif differ diff --git a/device/profusion/common/profusion-packages.mk b/device/profusion/common/profusion-packages.mk index b930303..61d7b99 100644 --- a/device/profusion/common/profusion-packages.mk +++ b/device/profusion/common/profusion-packages.mk @@ -1,2 +1,3 @@ # helloworld include packages/services/profusion/hello-world-service/helloworld-service.mk +include packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.mk diff --git a/device/profusion/profusion_sdk_addon/manifest.ini b/device/profusion/profusion_sdk_addon/manifest.ini index 5ac9a01..eb98f1f 100755 --- a/device/profusion/profusion_sdk_addon/manifest.ini +++ b/device/profusion/profusion_sdk_addon/manifest.ini @@ -12,6 +12,7 @@ api=34 revision=1 -libraries=helloworld +libraries=helloworld; DummyCarInfoManager helloworld=helloworld.jar +DummyCarInfoManager=DummyCarInfoManager.jar diff --git a/device/profusion/profusion_sdk_addon/package.xml b/device/profusion/profusion_sdk_addon/package.xml index 0e871df..0f27c4f 100644 --- a/device/profusion/profusion_sdk_addon/package.xml +++ b/device/profusion/profusion_sdk_addon/package.xml @@ -12,9 +12,12 @@ ProfusionAddOn - - Hello World Library - + + Hello World Library + + + Dummy Car Info Library + diff --git a/device/profusion/profusion_sdk_addon/profusion_sdk_addon.mk b/device/profusion/profusion_sdk_addon/profusion_sdk_addon.mk index 77cdc8a..52f6129 100644 --- a/device/profusion/profusion_sdk_addon/profusion_sdk_addon.mk +++ b/device/profusion/profusion_sdk_addon/profusion_sdk_addon.mk @@ -11,7 +11,13 @@ PRODUCT_SDK_ADDON_NAME := profusion_sdk_addon INTERNAL_SDK_HOST_OS_NAME := $(HOST_OS) PRODUCT_PACKAGES := \ - helloworld + libvsomeip3 \ + libCommonAPI \ + libCommonAPI-SomeIP \ + helloworld \ + profusion.hardware.dummy_car_info_hal-service \ + some_ip_playground-service \ + DummyCarInfoManager # Copy the manifest and hardware files for the SDK add-on. PRODUCT_SDK_ADDON_COPY_FILES := \ @@ -22,10 +28,17 @@ PRODUCT_SDK_ADDON_COPY_FILES := \ # Define the IMAGE PROPERTY (emulator related, but needed to build) PRODUCT_SDK_ADDON_SYS_IMG_SOURCE_PROP := $(LOCAL_PATH)/source.properties +BOARD_SEPOLICY_DIRS += \ + device/profusion/sepolicy/daemon \ + device/profusion/sepolicy/interface + +DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE += \ + hardware/implementations/dummy_car_info_hal/default/compatibility_matrix.xml # Copy the jar files for the optional libraries that are exposed as APIs. PRODUCT_SDK_ADDON_COPY_MODULES := \ - helloworld:libs/helloworld.jar + helloworld:libs/helloworld.jar \ + DummyCarInfoManager:libs/DummyCarInfoManager.jar # Rules for public APIs PRODUCT_SDK_ADDON_STUB_DEFS := $(LOCAL_PATH)/sdk_addon_stub_defs.txt diff --git a/device/profusion/profusion_sdk_addon/sdk_addon_stub_defs.txt b/device/profusion/profusion_sdk_addon/sdk_addon_stub_defs.txt index 176b24c..a9f4ba9 100755 --- a/device/profusion/profusion_sdk_addon/sdk_addon_stub_defs.txt +++ b/device/profusion/profusion_sdk_addon/sdk_addon_stub_defs.txt @@ -1 +1,2 @@ +com.profusion.helloworld.* ++com.profusion.dummyCarInfo.* diff --git a/device/profusion/sepolicy/daemon/dummy.te b/device/profusion/sepolicy/daemon/dummy.te new file mode 100644 index 0000000..4b6a17d --- /dev/null +++ b/device/profusion/sepolicy/daemon/dummy.te @@ -0,0 +1,13 @@ +type dummy_car_info_hal, domain; +type dummy_car_info_hal_exec, exec_type, file_type, vendor_file_type; + +init_daemon_domain(dummy_car_info_hal) + +binder_call(dummy_car_info_hal, hwservicemanager) + +allow dummy_car_info_hal servicemanager:binder { call transfer }; + +allow system_app dummy_car_info_hal:binder { call }; +allow platform_app dummy_car_info_hal:binder { call }; + +domain_auto_trans(init, dummy_car_info_hal_exec, dummy_car_info_hal) diff --git a/device/profusion/sepolicy/daemon/file_contexts b/device/profusion/sepolicy/daemon/file_contexts new file mode 100644 index 0000000..472c453 --- /dev/null +++ b/device/profusion/sepolicy/daemon/file_contexts @@ -0,0 +1,2 @@ +/vendor/bin/hw/profusion.hardware.dummy_car_info_hal-service u:object_r:dummy_car_info_hal_exec:s0 +/vendor/bin/some_ip_playground-service u:object_r:some_ip_playground-service_exec:s0 diff --git a/device/profusion/sepolicy/daemon/someip.te b/device/profusion/sepolicy/daemon/someip.te new file mode 100644 index 0000000..6930bd8 --- /dev/null +++ b/device/profusion/sepolicy/daemon/someip.te @@ -0,0 +1,12 @@ +type some_ip_playground-service, domain; +type some_ip_playground-service_exec, exec_type, file_type, vendor_file_type; + +init_daemon_domain(some_ip_playground-service) + +allow some_ip_playground-service sysfs:file { open read }; +allow some_ip_playground-service vendor_data_file:dir { add_name remove_name write }; +allow some_ip_playground-service vendor_data_file:file { create open read write lock }; +allow some_ip_playground-service vendor_data_file:sock_file { create setattr read write unlink}; +allow some_ip_playground-service self:netlink_route_socket { create bind shutdown nlmsg_read nlmsg_readpriv read write }; +allow some_ip_playground-service self:tcp_socket create; +allow some_ip_playground-service self:udp_socket { create ioctl }; diff --git a/device/profusion/sepolicy/interface/service.te b/device/profusion/sepolicy/interface/service.te new file mode 100644 index 0000000..933baea --- /dev/null +++ b/device/profusion/sepolicy/interface/service.te @@ -0,0 +1,4 @@ +type dummy_server_service, hal_service_type, protected_service, service_manager_type; + +allow dummy_car_info_hal dummy_server_service:service_manager add; +allow platform_app dummy_server_service:service_manager find; diff --git a/device/profusion/sepolicy/interface/service_contexts b/device/profusion/sepolicy/interface/service_contexts new file mode 100644 index 0000000..ba4c46f --- /dev/null +++ b/device/profusion/sepolicy/interface/service_contexts @@ -0,0 +1 @@ +profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL/default u:object_r:dummy_server_service:s0 diff --git a/doc/HAL.md b/doc/HAL.md new file mode 100644 index 0000000..e5bd290 --- /dev/null +++ b/doc/HAL.md @@ -0,0 +1,398 @@ +# HAL +The Hardware Abstraction Layer (HAL) can be understood as a layer that abstracts the hardware details from the rest of the system. In this repository, we are implementing a dummy HAL that provides car information, as if this information was coming from a sensor through a communication protocol or something like that. We also provide a way for third-party applications to access this information through the SDK-Addon, improving what is proposed in the **hello-world-service** example. So, is **highly** recommended to read the **hello-world-service** example before continuing with this one. + +## Files related to the HAL + +* `hardware/interfaces/dummy_car_info_hal`: This directory contains the AIDL files that define the interface of the HAL. +* `hardware/implementations/dummy_car_info_hal`: This directory contains the C++ implementation for the HAL at `DummyCarInfo.cpp`, the code that binds the HAL on the system boot at `service.cpp` and some configuration files to build the HAL. +* `package/services/profusion/dummy-car-info-service`: Contains the service that communicates with the `dummy_car_info_hal` and a Manager that binds this service and is exposed to 3rd party applications through the SDK-Addon. + +## Understading the key files + +Lets take a look at the key files in the HAL implementation: + +### The HAL service itself + +#### `IDummyCarInfoHAL.aidl` +``` java +package profusion.hardware.dummy_car_info_hal; + +@VintfStability +interface IDummyCarInfoHAL{ + void getCarInfo(out profusion.hardware.dummy_car_info_hal.CarInfo carInfo); +} +``` + +#### `CarInfo.aidl` +``` java +package profusion.hardware.dummy_car_info_hal; + +@VintfStability +parcelable CarInfo{ + int velocity; + int gear; + int fuel; +} +``` + +The first .aidl file defines the interface that the HAL service should implement, signalizing that the method `getCarInfo` will output a `CarInfo` object (note that **this isn't a return**, the method actually receives an object and fills it with the information using reference). The second .aidl file defines the `CarInfo` itself. + +Before any full compilation, it is necessary to run the `m profusion.hardware.dummy_car_info_hal-update-api` command to freeze and version the AIDL interfaces, which will generate the `hardware/interfaces/dummy_car_info_hal/aidl/aidl_api` directory at the AOSP source tree. + +#### `hardware/intefaces/dummy_car_info_hal/aidl/Android.bp` +``` +package { + default_applicable_licenses: ["hardware_interfaces_license"], +} + +aidl_interface { + name: "profusion.hardware.dummy_car_info_hal", + srcs: ["profusion/hardware/dummy_car_info_hal/*.aidl"], + stability: "vintf", + vendor_available: true, + backend: { + cpp: { + enabled: false, + }, + java: { + sdk_version: "module_current", + }, + }, + owner: "Profusion", +} + +``` + +Defines the AIDL interfaces to the build system. The 'stability: "vintf"' indicates that these are [Stable AIDLs](https://source.android.com/docs/core/architecture/aidl/stable-aidl). + +#### `DummyCarInfoHAL.h` +```cpp +#pragma once + +#include +#include + +namespace aidl { +namespace profusion { +namespace hardware { +namespace dummy_car_info_hal { + +class DummyCarInfoHAL : public BnDummyCarInfoHAL { + virtual ndk::ScopedAStatus getCarInfo(CarInfo* carInfo) override; + +protected: + std::mutex dummyCarInfoMutex; +}; + +} +} +} +} +``` + +`DummyCarInfoHAL.h` defines the class that implements the definitions of `IDummyCarInfoHAL` AIDL interface, once it inherits from the `Bn` class, which is auto-generated by the build system. It also defines a mutex to prevent simultaneous access to the car information. + +#### `DummyCarInfoHAL.cpp` +```cpp +#include "DummyCarInfoHAL.h" + +#include + +namespace aidl { +namespace profusion { +namespace hardware { +namespace dummy_car_info_hal { + +ndk::ScopedAStatus DummyCarInfoHAL::getCarInfo(CarInfo* carInfo) { + std::unique_lock lock(dummyCarInfoMutex); + LOG(INFO) << "DummyHAL: getCarInfo called!"; + carInfo->velocity = 100; + carInfo->fuel = 50; + carInfo->gear = 4; + return ndk::ScopedAStatus::ok(); +} + +} +} +} +} +``` + +The `DummyCarInfoHAL.cpp` implements the `getCarInfo` method. This method is responsible for filling the `CarInfo` object with the dummy car information. Note that here we are not instantiating the `CarInfo` object, instead, we are filling the object that was passed as a parameter to the method. We use `ndk::ScopedAStatus` to handle the completion of the method. Here we have a simple implementation that always returns `ok`, but is possible to handle errors as well. + +#### `service.cpp` +```cpp +#include "DummyCarInfoHAL.h" + +#include +#include +#include + +using aidl::profusion::hardware::dummy_car_info_hal::DummyCarInfoHAL; + +int main() { + LOG(INFO) << "DummyHAL: Main HAL being called"; + + ABinderProcess_setThreadPoolMaxThreadCount(0); + + std::shared_ptr dummyCarInfoHAL = ndk::SharedRefBase::make(); + + const std::string instance = std::string() + DummyCarInfoHAL::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(dummyCarInfoHAL->asBinder().get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); + + ABinderProcess_joinThreadPool(); + LOG(INFO) << "DummyHAL: Main HAL exiting main"; + return EXIT_FAILURE; +} +``` + +The `service.cpp` is responsible for binding the HAL service at the ServiceManager, allowing other processes and services to communicate with it. It also starts the thread pool to handle the incoming requests. It's important to note that is expected that `ABinderProcess_joinThreadPool();` never returns, so the `return EXIT_FAILURE;` acts more like a placeholder. + +#### `hardware/implementations/dummy_car_info_hal/default/Android.bp` +``` +cc_library_static { + name: "profusion.hardware.dummy_car_info_hal-lib", + srcs: [ + "DummyCarInfoHAL.cpp", + "service.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "profusion.hardware.dummy_car_info_hal-V1-ndk", + "libbase", + "liblog", + "libbinder_ndk", + ], + vendor: true, +} + +cc_binary { + name: "profusion.hardware.dummy_car_info_hal-service", + relative_install_path: "hw", + init_rc: ["dummy_car_info-default.rc"], + vintf_fragments: ["dummy_car_info-default.xml"], + srcs: [ + "DummyCarInfoHAL.cpp", + "service.cpp", + ], + static_libs: [ + "profusion.hardware.dummy_car_info_hal-lib", + ], + shared_libs: [ + "profusion.hardware.dummy_car_info_hal-V1-ndk", + "libbase", + "liblog", + "libbinder_ndk", + ], + vendor: true, +} +``` + +This `Android.bp` defines the build rules for the HAL service. `profusion.hardware.dummy_car_info_hal-V1-ndk` is the library that contains the generated code from AIDL interfaces. Lastly, the binary `profusion.hardware.dummy_car_info_hal-service` is installed at the `vendor/hw` directory and is referenced at the init_rc as shown below to bind the service at the system boot. + +#### `dummy_car_info-default.rc` +``` +service profusion.hardware.dummy_car_info_hal-service /vendor/bin/hw/profusion.hardware.dummy_car_info_hal-service + interface aidl profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL/default + class hal + user nobody + group nobody +``` + +The `dummy_car_info-default.rc` file defines the rules to start the HAL service, creating a link between the interface and the binary previously defined. In this case, it will be started at system boot, as the property `disabled` was omitted (for more informations, see [Dynamically available HAL](https://source.android.com/docs/core/architecture/hal/dynamic-lifecycle)). + +### SELinux policies for the services + +Android uses SELinux to enforce access control to resources like files, services, and so on. By default, everything is denied, so we need to explicitly indicate what our HAL Service is allowed to do and what processes are allowed to communicate with it. The policies need to be attached to a `TARGET_PRODUCT`, so we define them at the `device/profusion/sepolicy` directory. Also, the policies need to be included in the `.mk` file. In our case, we can achieve this by adding the following lines to the `device/profusion/profusion_sdk_addon.mk`: + +``` +BOARD_SEPOLICY_DIRS += \ + device/profusion/sepolicy/daemon \ + device/profusion/sepolicy/interface +``` + +And of course, the policies files: + +#### `file_contexts` +``` +/vendor/bin/hw/profusion.hardware.dummy_car_info_hal-service u:object_r:dummy_car_info_hal_exec:s0 +``` + +#### `dummy.te` +``` +type dummy_car_info_hal, domain; +type dummy_car_info_hal_exec, exec_type, file_type, vendor_file_type; + +init_daemon_domain(dummy_car_info_hal) + +binder_call(dummy_car_info_hal, hwservicemanager) + +allow dummy_car_info_hal servicemanager:binder { call transfer }; + +allow system_app dummy_car_info_hal:binder { call }; +allow platform_app dummy_car_info_hal:binder { call }; + +domain_auto_trans(init, dummy_car_info_hal_exec, dummy_car_info_hal) +``` + +In this files, we define and associate the context and the domain to our policies. Allowing the domain of `dummy_car_info_hal` to communicate with the `ServiceManager`, and allowing the `system_app` (service from packages) and `platform_app` (application) to communicate with the `dummy_car_info_hal`. + +#### `service_contexts` +``` +profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL/default u:object_r:dummy_server_service:s0 +``` + +#### `service.te` +``` +type dummy_server_service, hal_service_type, protected_service, service_manager_type; + +allow dummy_car_info_hal dummy_server_service:service_manager add; +allow platform_app dummy_server_service:service_manager find; + +``` + +In this files we define the policies for the service that is bounded at system boot. We allow that the `dummy_car_info_hal` context can add the `dummy_server_service` to the `ServiceManager` and that the `platform_app` can find this service. + +PS: More information about SELinux policies can be found at the [Android Developer Documentation](https://source.android.com/docs/security/features/selinux/implement). + +### Files related to the SDK + +#### `DummyCarInfoService.java` +```java +... + @Override + public void onCreate() { + super.onCreate(); + Log.d(TAG, "onCreate"); + try { + IBinder binder = ServiceManager.getService("profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL/default"); + if (binder == null) { + Log.e(TAG, "Failed to get DummyCarInfoHAL from ServiceManager"); + return; + } + halService = IDummyCarInfoHAL.Stub.asInterface(binder); + if (halService == null) { + Log.e(TAG, "Failed to get DummyCarInfoHAL service"); + return; + } + Log.d(TAG, "HAL binded"); + } catch (Exception e) { + Log.e(TAG, "Exception on HAL bind", e); + } + } +... + private String getCarInfoFromHAL() throws Exception { + Log.d(TAG, "Getting car info from HAL"); + if (halService != null) { + try { + CarInfo carInfo = new CarInfo(); + halService.getCarInfo(carInfo); + Log.d(TAG, "Car info received from HAL"); + return "Velocity: " + carInfo.velocity + ", Fuel: " + carInfo.fuel + ", Gear: " + carInfo.gear; + } catch (Exception e) { + Log.e(TAG, "Exception on getCarInfo", e); + throw new Exception("Failed to get car info from HAL", e); + } + } else { + Log.e(TAG, "HAL service is not initialized"); + throw new Exception("HAL service is not initialized"); + } + } +``` + +Beyond what we already know of the `hello-world-service`, this one uses the ServiceManager to retrieve an instance of the HAL Service that was bonded at the system boot. In this way, we can establish communication between the two different layers without concerns about languages and implementations. To retrieve the car information, we simply need to call the `getCarInfo` method passing an instance of the CarInfo object. + +#### `DummyCarInfoManager.java` +```java +public class DummyCarInfoManager { + private static final String TAG = "DummyCarInfoManager"; + private IDummyCarInfoService dummyCarInfoService; + private Context context; + private boolean isBound = false; + private static final String DUMMY_CAR_SERVICE_PACKAGE = "com.profusion.dummyCarInfo"; + private static final String DUMMY_CAR_SERVICE = "com.profusion.dummyCarInfo.DummyCarInfoService"; + + public DummyCarInfoManager(Context context) { + this.context = context; + bindService(); + } + + private void bindService() { + try { + Intent intent = new Intent(); + intent.setComponent(new ComponentName(DUMMY_CAR_SERVICE_PACKAGE, DUMMY_CAR_SERVICE)); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + Log.e(TAG, "Exception while binding to DummyCarInfoService", e); + } + } + + public void unbindService() { + if (isBound) { + context.unbindService(serviceConnection); + isBound = false; + } + } + + private ServiceConnection serviceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + dummyCarInfoService = IDummyCarInfoService.Stub.asInterface(service); + isBound = true; + Log.d(TAG, "DummyCarInfoService connected"); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + dummyCarInfoService = null; + isBound = false; + Log.d(TAG, "DummyCarInfoService disconnected"); + } + }; + + public String getCarInfo() throws Exception { + if (dummyCarInfoService != null) { + String carInfo = dummyCarInfoService.getCarInfo(); + if (carInfo != null) { + return carInfo; + } else { + Log.e(TAG, "Failed to get car info from DummyCarInfoService"); + throw new Exception("Failed to get car info from DummyCarInfoService"); + } + } else { + Log.e(TAG, "DummyCarInfoService is not bound"); + throw new Exception("DummyCarInfoService is not bound"); + } + } +} +``` + +Instead of exposing the `DummyCarInfoService` (as we did in the `hello-world-service`), here we define a `DummyCarInfoManager` that is responsible for binding the service and retrieving the car information. This way, we can abstract the service from the application, making it easier to 3rd party applications to use it. + +The remaining build files are very similar to the `hello-world-service` example, so we are not going to detail them here. The main difference is that we need to include the `profusion.hardware.dummy_car_info_hal-service` module in the `PRODUCT_PACKAGES` variable at `device/profusion/profusion_sdk_addon.mk` file. + +## Using the Manager in a application + +The add-on that was added to Android Studio following [Adding the SDK Add-on to Android Studio](../README.md#adding-the-sdk-add-on-to-android-studio) already contains the `.jar` for the `DummyCarInfoManager`, then to use it in an application (after adding the SDK Add-on as a dependency on `build.gradle`) you just need to import the class, create an instance of it and call the `getCarInfo` method. + +```kotlin +import com.profusion.dummyCarInfo.DummyCarInfoManager +... +override fun onStart() { + super.onStart() + dummyCarInfoManager = DummyCarInfoManager(this) +} +... +fun getCarInfo() : String { + return dummyCarInfoManager.getCarInfo() +} +``` + +## Building and running + +If you followed the instructions of the [Building the SDK Addon](../README.md#building-the-sdk-addon) section in README, you already have an emulator with the system image containing the HAL and the SDK. All you need to do is run the emulator and install the sample app! + +![App with button to call DummyCarInfoManager](../assets/running_app_hal.gif) diff --git a/doc/SOME-IP-HAL.md b/doc/SOME-IP-HAL.md new file mode 100644 index 0000000..334406e --- /dev/null +++ b/doc/SOME-IP-HAL.md @@ -0,0 +1,105 @@ +# HAL with SOME/IP and CommonAPI +The idea is that at some moment this repository also contains an implementation of a HAL that uses SOME/IP (through CommonAPI). The `hardware/implementations/some_ip_hal` directory already has some files related to the PlaygroundService, which will provide some mocked data through SOME/IP. +This PlaygroundService module is based on the implementation that can be found at [test-someip-service](https://github.com/COVESA/test-someip-service). + +## About version + +In this implementation, we use `capicxx-someip-runtime`, `capicxx-core-runtime`, and respective generators at version `3.2.0`. This version was chosen because we faced some problems when trying to compile the most recent versions, due to the vsomeip that comes with AOSP on API 34 don't have the rule to make `libsomeip3_dlt` and `libboost_log`, which are dependencies required by versions `<3.2.3`. + +## CommonAPI Files +At this documentation, I will not go deeper into CommonAPI framework concepts. If you want to know more about it, please refer to the [CommonAPI documentation](https://covesa.github.io/capicxx-core-tools/). + +#### `hardware/implementation/some_ip_hal/franca` +This directory contains the Franca files that will be used to generate the CommonAPI files. The `.fdepl` and `.fidl` files here are strictly the same as the ones used in [test-someip-service](https://github.com/COVESA/test-someip-service). These files define how CommonAPI should generate files to provide information about a vehicle, such as speed, gear, fuel level, etc. + +#### `hardware/implementation/some_ip_hal/default/playground_service/mock` +This directory contains the mock values that will be used by the PlaygroundService to provide information about the vehicle. + +#### `hardware/implementation/some_ip_hal/default/include` +This directory will contain the generated CommonAPI files. Commands to generate these files are shown below. + +#### `hardware/implementation/some_ip_hal/default/playground_service/PlaygroundStubImpl.cpp` and `hardware/implementation/some_ip_hal/default/playground_service/PlaygroundStubImpl.hpp` +These files contain the implementation to `PlaygroundStubDefault`, which is basically the class that will provide the information about the vehicle to the PlaygroundService. Note that in `PlaygroundStubImpl.hpp` all the attributes come from the `Mock` class. + +#### `hardware/implementation/some_ip_hal/default/playground_service/PlaygroundService.cpp` +```cpp +... +using namespace std; + +int main() { + std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl; + std::shared_ptr runtime = CommonAPI::Runtime::get(); + std::shared_ptr playgroundService = + std::make_shared(); + runtime->registerService("local", "1", playgroundService); + std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl; + + while (true) { + playgroundService->updateTankVolume(); + playgroundService->monitorTankLevel(); + std::cout << "SOMEIPPlayground: Waiting for calls..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + return 0; + } +``` + +This file contains the main function of the PlaygroundService. The principal responsibility of this file is to register a service using the `PlaygroundStubImpl`. Also, this main function will loop indefinitely simulating the vehicle use, and updating the tank volume. + +### Generating CommonAPI Files + +Since you already cloned the necessary libs using `fetch_someip_libs.sh`, generate CommonAPI is very simple. To generate core files run: + +```bash +./libs/someip-generators/commonapi_core_generator/commonapi-core-generator-linux-x86 -nv -sk \ +--dest "hardware/implementations/some_ip_hal/default/include" \ +hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl +``` + +And to generate SOME/IP files run: + +```bash +./libs/someip-generators/commonapi_someip_generator/commonapi-someip-generator-linux-x86 -nv \ +--dest "hardware/implementations/some_ip_hal/default/include" \ +hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl +``` + +### Its necessary to start the service manualy? +No, the service will be started automatically through the `some_ip_playground-init.rc` file at Android boot: + +``` +service some_ip_playground-service /vendor/bin/some_ip_playground-service + class main + user none + group none + disabled + setenv VSOMEIP_APPLICATION_NAME playground-service + setenv VSOMEIP_CONFIGURATION /vendor/etc/some_ip_playground/vsomeip.json + setenv VSOMEIP_BASE_PATH /data/vendor/vsomeip/ + +on property:sys.boot_completed=1 + mkdir /data/vendor/vsomeip 0771 none none + start some_ip_playground-service +``` + +This file defines the necessary environment variables to start the service and also starts the service when the property `sys.boot_completed` is set to 1. Another important part is to create the directory `/data/vendor/vsomeip` where the vsomeip files will be located. This path will also be important when starting our HAL. + +## Verify if Playground Service is running + +To verify if the Playground Service is running, you can check the logcat output. With the emulator running, open a terminal and run this command: + +```bash +adb shell logcat | grep some_ip +``` + +If the output is something like that, everything is working fine: + +![Logcat of some_ip](../assets/playground_service_log.png "Logcat of some_ip") + +## Next steps + +The next step is to implement the HAL that will communicate with the Playground Service. Probably, the first step is to create a class responsible for instantiating and handling the communication with `PlaygroundSomeIPProxy`, as it will be more sophisticated than handling everything in the HAL. + +About the HAL, I would say that this implementation could be a good opportunity to understand how to communicate between application and the HAL using callbacks since it's a common pattern in Android development. Maybe register a callback to receive the car information updated by a loop in the Playground Service or something like that. + +Another thing that is not exactly clear to me is if we should expose the AIDL interface from HAL in the sdk-addon to get a return of types and not only strings from the Manager or if we should create a new AIDL interface under the `packages` directory and map between the two interfaces. I think that this is an important point to discuss and understand the best approach. diff --git a/fetch_someip_libs.sh b/fetch_someip_libs.sh new file mode 100644 index 0000000..9e9f210 --- /dev/null +++ b/fetch_someip_libs.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +echo "Clonning COMMONAPI libs" +if [ ! -d "libs" ]; then + mkdir libs +fi +cd libs +if [ ! -d "capicxx-someip-runtime" ]; then + git clone -b 3.2.0 https://github.com/COVESA/capicxx-someip-runtime.git capicxx-someip-runtime + sed -i '26s/.*/ "libvsomeip3",/' capicxx-someip-runtime/Android.bp +fi +if [ ! -d "capicxx-core-runtime" ]; then + git clone -b 3.2.0 https://github.com/COVESA/capicxx-core-runtime.git capicxx-core-runtime +fi +mkdir -p someip-generators +if [ ! -d "someip-generators/commonapi_someip_generator" ]; then + wget https://github.com/COVESA/capicxx-someip-tools/releases/download/3.2.0.1/commonapi_someip_generator.zip + unzip commonapi_someip_generator.zip -d someip-generators/commonapi_someip_generator + rm commonapi_someip_generator.zip +fi +if [ ! -d "someip-generators/commonapi_core_generator" ]; then + wget https://github.com/COVESA/capicxx-core-tools/releases/download/3.2.0.1/commonapi_core_generator.zip + unzip commonapi_core_generator.zip -d someip-generators/commonapi_core_generator + rm commonapi_core_generator.zip +fi diff --git a/hardware/implementations/dummy_car_info_hal/default/Android.bp b/hardware/implementations/dummy_car_info_hal/default/Android.bp new file mode 100644 index 0000000..b4a1c2b --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/Android.bp @@ -0,0 +1,38 @@ +cc_library_static { + name: "profusion.hardware.dummy_car_info_hal-lib", + srcs: [ + "DummyCarInfoHAL.cpp", + "service.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "profusion.hardware.dummy_car_info_hal-V1-ndk", + "libbase", + "liblog", + "libbinder_ndk", + ], + vendor: true, +} + +cc_binary { + name: "profusion.hardware.dummy_car_info_hal-service", + relative_install_path: "hw", + init_rc: ["dummy_car_info-default.rc"], + vintf_fragments: ["dummy_car_info-default.xml"], + srcs: [ + "DummyCarInfoHAL.cpp", + "service.cpp", + ], + static_libs: [ + "profusion.hardware.dummy_car_info_hal-lib", + ], + shared_libs: [ + "profusion.hardware.dummy_car_info_hal-V1-ndk", + "libbase", + "liblog", + "libbinder_ndk", + ], + vendor: true, +} diff --git a/hardware/implementations/dummy_car_info_hal/default/DummyCarInfoHAL.cpp b/hardware/implementations/dummy_car_info_hal/default/DummyCarInfoHAL.cpp new file mode 100644 index 0000000..f9b9c6a --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/DummyCarInfoHAL.cpp @@ -0,0 +1,28 @@ +#include "DummyCarInfoHAL.h" + +#include +#include + +namespace aidl { +namespace profusion { +namespace hardware { +namespace dummy_car_info_hal { + +ndk::ScopedAStatus DummyCarInfoHAL::getCarInfo(CarInfo* carInfo) { + if (carInfo == nullptr) { + LOG(ERROR) << "DummyHAL: carInfo is null!"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + std::unique_lock lock(dummyCarInfoMutex); + LOG(INFO) << "DummyHAL: getCarInfo called!"; + carInfo->velocity = rand() % 70 + 50; + carInfo->fuel = rand() % 10 + 50; + carInfo->gear = rand() % 5 + 1; + return ndk::ScopedAStatus::ok(); +} + +} +} +} +} diff --git a/hardware/implementations/dummy_car_info_hal/default/compatibility_matrix.xml b/hardware/implementations/dummy_car_info_hal/default/compatibility_matrix.xml new file mode 100644 index 0000000..2afdacc --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/compatibility_matrix.xml @@ -0,0 +1,10 @@ + + + profusion.hardware.dummy_car_info_hal + 1 + + IDummyCarInfoHAL + default + + + diff --git a/hardware/implementations/dummy_car_info_hal/default/dummy_car_info-default.rc b/hardware/implementations/dummy_car_info_hal/default/dummy_car_info-default.rc new file mode 100644 index 0000000..5bbca2c --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/dummy_car_info-default.rc @@ -0,0 +1,5 @@ +service profusion.hardware.dummy_car_info_hal-service /vendor/bin/hw/profusion.hardware.dummy_car_info_hal-service + interface aidl profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL/default + class hal + user nobody + group nobody diff --git a/hardware/implementations/dummy_car_info_hal/default/dummy_car_info-default.xml b/hardware/implementations/dummy_car_info_hal/default/dummy_car_info-default.xml new file mode 100644 index 0000000..81ddb0d --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/dummy_car_info-default.xml @@ -0,0 +1,7 @@ + + + profusion.hardware.dummy_car_info_hal + 1 + IDummyCarInfoHAL/default + + diff --git a/hardware/implementations/dummy_car_info_hal/default/include/DummyCarInfoHAL.h b/hardware/implementations/dummy_car_info_hal/default/include/DummyCarInfoHAL.h new file mode 100644 index 0000000..04edebd --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/include/DummyCarInfoHAL.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace aidl { +namespace profusion { +namespace hardware { +namespace dummy_car_info_hal { + +class DummyCarInfoHAL : public BnDummyCarInfoHAL { + virtual ndk::ScopedAStatus getCarInfo(CarInfo* carInfo) override; + +protected: + std::mutex dummyCarInfoMutex; +}; + +} +} +} +} diff --git a/hardware/implementations/dummy_car_info_hal/default/service.cpp b/hardware/implementations/dummy_car_info_hal/default/service.cpp new file mode 100644 index 0000000..687cf59 --- /dev/null +++ b/hardware/implementations/dummy_car_info_hal/default/service.cpp @@ -0,0 +1,23 @@ +#include "DummyCarInfoHAL.h" + +#include +#include +#include + +using aidl::profusion::hardware::dummy_car_info_hal::DummyCarInfoHAL; + +int main() { + LOG(INFO) << "DummyHAL: Main HAL being called"; + + ABinderProcess_setThreadPoolMaxThreadCount(0); + + std::shared_ptr dummyCarInfoHAL = ndk::SharedRefBase::make(); + + const std::string instance = std::string() + DummyCarInfoHAL::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(dummyCarInfoHAL->asBinder().get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); + + ABinderProcess_joinThreadPool(); + LOG(INFO) << "DummyHAL: Main HAL initialization failed"; + return EXIT_FAILURE; +} diff --git a/hardware/implementations/some_ip_hal/.gitignore b/hardware/implementations/some_ip_hal/.gitignore new file mode 100644 index 0000000..d43c532 --- /dev/null +++ b/hardware/implementations/some_ip_hal/.gitignore @@ -0,0 +1 @@ +default/include/* diff --git a/hardware/implementations/some_ip_hal/default/Android.bp b/hardware/implementations/some_ip_hal/default/Android.bp new file mode 100644 index 0000000..9fe380e --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/Android.bp @@ -0,0 +1,55 @@ +cc_defaults { + name: "some_ip_playground-defaults", + vendor: true, + rtti: true, + cppflags: [ + "-fexceptions", + "-Wall", + "-Werror", + "-Wno-ignored-attributes", + "-Wno-unused-parameter", + "-Wno-overloaded-virtual", + "-DCOMMONAPI_INTERNAL_COMPILATION", + ], + + shared_libs: [ + "libvsomeip3-cfg", + "libvsomeip3", + "libCommonAPI", + "libCommonAPI-SomeIP", + "libbase", + ], +} + +runtime_required = [ + "some_ip_playground-vsomeip.json", +] + +prebuilt_etc { + name: "some_ip_playground-vsomeip.json", + vendor: true, + sub_dir: "some_ip_playground", + src: "vsomeip.json", + filename:"vsomeip.json" +} + +cc_binary { + name: "some_ip_playground-service", + defaults: [ + "some_ip_playground-defaults", + ], + init_rc: ["playground_service/some_ip_playground-init.rc"], + local_include_dirs: [ + "playground_service/mock", + "include", + ], + srcs: [ + "playground_service/PlaygroundService.cpp", + "playground_service/PlaygroundStubImpl.cpp", + "include/v1/org/genivi/vehicle/playground/PlaygroundSomeIPDeployment.cpp", + "include/v1/org/genivi/vehicle/playground/PlaygroundSomeIPStubAdapter.cpp", + "playground_service/mock/MockedAttributes.cpp", + ], + required: runtime_required, + vendor: true, +} diff --git a/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundService.cpp b/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundService.cpp new file mode 100644 index 0000000..c783203 --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundService.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), + * Author: Alexander Domin (Alexander.Domin@bmw.de) + * Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, + * Author: Leandro Ferlin (leandroferlin@profusion.mobi) + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was + * not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include "PlaygroundStubImpl.hpp" + +using namespace std; + +int main() { + std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl; + std::shared_ptr runtime = CommonAPI::Runtime::get(); + std::shared_ptr playgroundService = + std::make_shared(); + runtime->registerService("local", "1", playgroundService); + std::cout << "SOMEIPPlayground: Successfully Registered Service!" << std::endl; + + while (true) { + playgroundService->updateTankVolume(); + playgroundService->monitorTankLevel(); + std::cout << "SOMEIPPlayground: Waiting for calls..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + return 0; + } + \ No newline at end of file diff --git a/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundStubImpl.cpp b/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundStubImpl.cpp new file mode 100644 index 0000000..1c9d608 --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundStubImpl.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), + * Author: Alexander Domin (Alexander.Domin@bmw.de) + * Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, + * Author: Leandro Ferlin (leandroferlin@profusion.mobi) + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was + * not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + */ + +#include "PlaygroundStubImpl.hpp" +#include "mock/MockedAttributes.hpp" +#include +#include +#include +#include +#include +#include + +typedef v1_0::org::genivi::vehicle::playground::PlaygroundStubDefault + PlaygroundStubDefault; + +PlaygroundStubImpl::PlaygroundStubImpl() + : consumption{}, capacity{}, volume{}, engineSpeed{}, currentGear{}, + isReverseGearOn{}, drivePowerTransmission{}, doorsOpeningStatus{}, + seatHeatingStatus{}, seatHeatingLevel{} { + initializeAttributes(); +} +PlaygroundStubImpl::~PlaygroundStubImpl() {} + +void PlaygroundStubImpl::initializeAttributes() { + PlaygroundStubDefault::setConsumptionAttribute(consumption.getValue()); + PlaygroundStubDefault::setCapacityAttribute(capacity.getValue()); + PlaygroundStubDefault::setVolumeAttribute(volume.getValue()); + PlaygroundStubDefault::setEngineSpeedAttribute(engineSpeed.getValue()); + PlaygroundStubDefault::setCurrentGearAttribute(currentGear.getValue()); + PlaygroundStubDefault::setIsReverseGearOnAttribute( + isReverseGearOn.getValue()); + PlaygroundStubDefault::setDrivePowerTransmissionAttribute( + drivePowerTransmission.getValue()); + PlaygroundStubDefault::setDoorsOpeningStatusAttribute( + doorsOpeningStatus.getValue()); + PlaygroundStubDefault::setSeatHeatingStatusAttribute( + seatHeatingStatus.getValue()); + PlaygroundStubDefault::setSeatHeatingLevelAttribute( + seatHeatingLevel.getValue()); +} + +void PlaygroundStubImpl::updateTankVolume() { + const float currentVolume = PlaygroundStubDefault::getVolumeAttribute(); + float updatedVolume; + if (currentVolume > 0.0) { + updatedVolume = currentVolume - 0.1; + } else { + updatedVolume = capacity.getCapacityInLiters(); + } + PlaygroundStubDefault::setVolumeAttribute(updatedVolume); +} + +void PlaygroundStubImpl::monitorTankLevel() { + const double capacityInLiters = capacity.getCapacityInLiters(); + const int currentVolume = PlaygroundStubDefault::getVolumeAttribute(); + + const uint8_t &level = (uint8_t)(100 * currentVolume / capacityInLiters); + fireCurrentTankVolumeEvent(level); +} + +void PlaygroundStubImpl::changeDoorsState( + const std::shared_ptr _client, + CarDoorsCommand _commands, changeDoorsStateReply_t _reply) { + + DoorsStatus lockedDoorsStatus = + PlaygroundStubDefault::getDoorsOpeningStatusAttribute(); + + const bool ¤tFrontLeftState = lockedDoorsStatus.getFrontLeft(); + const bool ¤tFrontRightState = lockedDoorsStatus.getFrontRight(); + const bool ¤tRearLeftState = lockedDoorsStatus.getRearLeft(); + const bool ¤tRearRightState = lockedDoorsStatus.getRearRight(); + + const DoorCommand &frontLeftCommand = _commands.getFrontLeftDoor(); + const DoorCommand &frontRightCommand = _commands.getFrontRightDoor(); + const DoorCommand &rearLeftCommand = _commands.getRearLeftDoor(); + const DoorCommand &rearRightCommand = _commands.getRearRightDoor(); + + const bool &nextFrontLeftState = doorsOpeningStatus.getNextStateFromCommand( + currentFrontLeftState, frontLeftCommand); + const bool &nextFrontRightState = doorsOpeningStatus.getNextStateFromCommand( + currentFrontRightState, frontRightCommand); + const bool &nextRearLeftState = doorsOpeningStatus.getNextStateFromCommand( + currentRearLeftState, rearLeftCommand); + const bool &nextRearRightState = doorsOpeningStatus.getNextStateFromCommand( + currentRearRightState, rearRightCommand); + + const DoorsStatus &doorsStatus = + DoorsStatus(nextFrontLeftState, nextFrontRightState, nextRearLeftState, + nextRearRightState); + + PlaygroundStubDefault::setDoorsOpeningStatusAttribute(doorsStatus); + _reply(); +}; diff --git a/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundStubImpl.hpp b/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundStubImpl.hpp new file mode 100644 index 0000000..37cf045 --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/PlaygroundStubImpl.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), + * Author: Alexander Domin (Alexander.Domin@bmw.de) + * Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, + * Author: Leandro Ferlin (leandroferlin@profusion.mobi) + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was + * not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + */ + +#ifndef PLAYGROUNDSTUBIMPL_H_ +#define PLAYGROUNDSTUBIMPL_H_ +#include +#include +#include + +#include "mock/MockedAttributes.hpp" + +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::Gear Gear; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::DoorsStatus + DoorsStatus; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::DriveType + DriveType; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::DoorCommand + DoorCommand; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes:: + CarDoorsCommand CarDoorsCommand; +typedef CommonAPI::Event CurrentTankVolumeEvent; + +class PlaygroundStubImpl + : public v1_0::org::genivi::vehicle::playground::PlaygroundStubDefault { +private: + Mock::Consumption consumption; + Mock::Capacity capacity; + Mock::Volume volume; + Mock::EngineSpeed engineSpeed; + Mock::CurrentGear currentGear; + Mock::IsReverseGearOn isReverseGearOn; + Mock::DrivePowerTransmission drivePowerTransmission; + Mock::DoorsOpeningStatus doorsOpeningStatus; + Mock::SeatHeatingStatus seatHeatingStatus; + Mock::SeatHeatingLevel seatHeatingLevel; + +public: + PlaygroundStubImpl(); + virtual ~PlaygroundStubImpl(); + + void initializeAttributes(); + + void updateTankVolume(); + + void monitorTankLevel(); + + virtual void + changeDoorsState(const std::shared_ptr _client, + CarDoorsCommand _commands, changeDoorsStateReply_t _reply); +}; +#endif /* PLAYGROUNDSTUBIMPL_H_ */ diff --git a/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedAttributes.cpp b/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedAttributes.cpp new file mode 100644 index 0000000..2921d0b --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedAttributes.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), + * Author: Alexander Domin (Alexander.Domin@bmw.de) + * Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, + * Author: Leandro Ferlin (leandroferlin@profusion.mobi) + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was + * not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + */ + +#include "MockedAttributes.hpp" +#include + +namespace Mock { + +Consumption::Consumption(float v) : MockedValue{v} {}; + +Consumption::Consumption() : MockedValue{4.5} {}; + +Capacity::Capacity(uint8_t v, double minValue, double maxValue, + double maxValueInMilliliters) + : MockedValue{v}, m_MinValue(minValue), m_MaxValue(maxValue), + m_MaxValueInMilliliters(maxValueInMilliliters){}; + +Capacity::Capacity(uint8_t v) + : MockedValue{v}, m_MinValue(0.0), m_MaxValue(255.0), + m_MaxValueInMilliliters(80000.0){}; + +Capacity::Capacity() + : MockedValue{200}, m_MinValue(0.0), m_MaxValue(255.0), + m_MaxValueInMilliliters(80000.0){}; + +double Capacity::getMinValue() { return m_MinValue; } + +double Capacity::getMaxValue() { return m_MaxValue; } + +double Capacity::getMaxValueInMilliliters() { return m_MaxValueInMilliliters; } + +double Capacity::getCapacityInLiters() { + return m_MaxValueInMilliliters * (value / (m_MaxValue - m_MinValue)) / 1000; +} + +Volume::Volume(float v) : MockedValue{v} {}; + +Volume::Volume() : MockedValue{60.8} {}; + +EngineSpeed::EngineSpeed(uint16_t v) : MockedValue{v} {}; + +EngineSpeed::EngineSpeed() : MockedValue{2000} {}; + +CurrentGear::CurrentGear(Gear v) : MockedValue{v} {}; + +CurrentGear::CurrentGear() + : MockedValue{Gear(Gear::Literal::FOURTH_GEAR)} {}; + +IsReverseGearOn::IsReverseGearOn(bool v) : MockedValue{v} {}; + +IsReverseGearOn::IsReverseGearOn() : MockedValue{false} {}; + +DrivePowerTransmission::DrivePowerTransmission(DriveType v) + : MockedValue{v} {}; + +DrivePowerTransmission::DrivePowerTransmission() + : MockedValue{ + DriveType(DriveType::Literal::REAR_WHEEL_DRIVE)} {}; + +DoorsOpeningStatus::DoorsOpeningStatus(DoorsStatus v) + : MockedValue{v} {}; + +DoorsOpeningStatus::DoorsOpeningStatus() + : MockedValue{DoorsStatus(true, false, false, false)} {}; + +bool DoorsOpeningStatus::getNextStateFromCommand(const bool ¤tState, + const DoorCommand &command) { + if (command == DoorCommand::Literal::NOTHING) { + return currentState; + } + return (command == DoorCommand::Literal::OPEN_DOOR); +} + +SeatHeatingStatus::SeatHeatingStatus(std::vector v) + : MockedValue>{v} {}; + +SeatHeatingStatus::SeatHeatingStatus() + : MockedValue>{ + {true, true, false, true, false, true, false}} {}; + +SeatHeatingLevel::SeatHeatingLevel(std::vector v) + : MockedValue>{v} {}; + +SeatHeatingLevel::SeatHeatingLevel() + : MockedValue>{{50, 45, 30, 30, 60, 65, 70}} {}; + +} // namespace Mock diff --git a/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedAttributes.hpp b/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedAttributes.hpp new file mode 100644 index 0000000..52f68d0 --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedAttributes.hpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), + * Author: Alexander Domin (Alexander.Domin@bmw.de) + * Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, + * Author: Leandro Ferlin (leandroferlin@profusion.mobi) + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was + * not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + */ + +#ifndef CONSUMPTION_H_ +#define CONSUMPTION_H_ + +#include "MockedValue.hpp" +#include +#include +#include + +namespace Mock { + +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::Gear Gear; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::DoorsStatus + DoorsStatus; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::DriveType + DriveType; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes::DoorCommand + DoorCommand; +typedef ::org::genivi::vehicle::playgroundtypes::PlaygroundTypes:: + CarDoorsCommand CarDoorsCommand; +typedef CommonAPI::Event CurrentTankVolumeEvent; + +class Consumption : public MockedValue { + +public: + Consumption(float v); + Consumption(); +}; + +class Capacity : public MockedValue { + +private: + const double m_MinValue; + const double m_MaxValue; + const double m_MaxValueInMilliliters; + +public: + Capacity(uint8_t v, double minValue, double maxValue, + double maxValueInMilliliters); + Capacity(uint8_t v); + Capacity(); + + double getMinValue(); + double getMaxValue(); + double getMaxValueInMilliliters(); + double getCapacityInLiters(); +}; + +class Volume : public MockedValue { + +public: + Volume(float v); + Volume(); +}; + +class EngineSpeed : public MockedValue { + +public: + EngineSpeed(uint16_t v); + EngineSpeed(); +}; + +class CurrentGear : public MockedValue { + +public: + CurrentGear(Gear v); + CurrentGear(); +}; + +class IsReverseGearOn : public MockedValue { + +public: + IsReverseGearOn(bool v); + IsReverseGearOn(); +}; + +class DrivePowerTransmission : public MockedValue { + +public: + DrivePowerTransmission(DriveType v); + DrivePowerTransmission(); +}; + +class DoorsOpeningStatus : public MockedValue { + +public: + DoorsOpeningStatus(DoorsStatus v); + DoorsOpeningStatus(); + + bool getNextStateFromCommand(const bool ¤tState, + const DoorCommand &command); + bool getNextStateFromCommand(); +}; + +class SeatHeatingStatus : public MockedValue> { + +public: + SeatHeatingStatus(std::vector v); + SeatHeatingStatus(); +}; + +class SeatHeatingLevel : public MockedValue> { + +public: + SeatHeatingLevel(std::vector v); + SeatHeatingLevel(); +}; + +} // namespace Mock + +#endif diff --git a/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedValue.hpp b/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedValue.hpp new file mode 100644 index 0000000..663a18b --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/mock/MockedValue.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), + * Author: Alexander Domin (Alexander.Domin@bmw.de) + * Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, + * Author: Leandro Ferlin (leandroferlin@profusion.mobi) + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was + * not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + */ + +#ifndef MOCKED_VALUE_H_ +#define MOCKED_VALUE_H_ + +template class MockedValue { +protected: + T value; + +public: + MockedValue(T v) : value(v) {} + + T getValue() { return value; } +}; + +#endif diff --git a/hardware/implementations/some_ip_hal/default/playground_service/some_ip_playground-init.rc b/hardware/implementations/some_ip_hal/default/playground_service/some_ip_playground-init.rc new file mode 100644 index 0000000..f7b7a4d --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/playground_service/some_ip_playground-init.rc @@ -0,0 +1,12 @@ +service some_ip_playground-service /vendor/bin/some_ip_playground-service + class main + user none + group none + disabled + setenv VSOMEIP_APPLICATION_NAME playground-service + setenv VSOMEIP_CONFIGURATION /vendor/etc/some_ip_playground/vsomeip.json + setenv VSOMEIP_BASE_PATH /data/vendor/vsomeip/ + +on property:sys.boot_completed=1 + mkdir /data/vendor/vsomeip 0771 none none + start some_ip_playground-service diff --git a/hardware/implementations/some_ip_hal/default/vsomeip.json b/hardware/implementations/some_ip_hal/default/vsomeip.json new file mode 100644 index 0000000..7a896d8 --- /dev/null +++ b/hardware/implementations/some_ip_hal/default/vsomeip.json @@ -0,0 +1,21 @@ +{ + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "playground-service", + "id" : "0x4444" + } + ], + "routing" : "playground-service", + "service-discovery" : + { + "enable" : "false" + } +} diff --git a/hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl b/hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl new file mode 100644 index 0000000..8ed2b8c --- /dev/null +++ b/hardware/implementations/some_ip_hal/franca/instances/org.genivi.vehicle.playground.fdepl @@ -0,0 +1,28 @@ +/* +* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), +* Author: Alexander Domin (Alexander.Domin@bmw.de) +* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, +* Author: Leonardo Ramos (leo.ramos@profusion.mobi) +* +* SPDX-License-Identifier: MPL-2.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was +* not distributed with this file, You can obtain one at +* http://mozilla.org/MPL/2.0/. +*/ + +import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-SOMEIP_deployment_spec.fdepl" +import "../org/genivi/vehicle/playground.fdepl" +import "../org/genivi/vehicle/playground.fidl" + +define org.genivi.commonapi.someip.deployment for provider as +org.genivi.vehicle.playground { + instance org.genivi.vehicle.playground.Playground as PlaygroundInst1 { + SomeIpInstanceID = 1 + InstanceId = "1" + SomeIpUnicastAddress = "" + SomeIpReliableUnicastPort = 0 + SomeIpUnreliableUnicastPort = 0 + } +} diff --git a/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playground.fdepl b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playground.fdepl new file mode 100644 index 0000000..aabcb82 --- /dev/null +++ b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playground.fdepl @@ -0,0 +1,120 @@ +/* +* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), +* Author: Alexander Domin (Alexander.Domin@bmw.de) +* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, +* Author: Leonardo Ramos (leo.ramos@profusion.mobi) +* +* SPDX-License-Identifier: MPL-2.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was +* not distributed with this file, You can obtain one at +* http://mozilla.org/MPL/2.0/. +*/ + +import +"platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-4-SOMEIP_deployment_spec.fdepl" +import "playground.fidl" +import "playgroundTypes.fidl" +import "playgroundTypes.fdepl" + +define org.genivi.commonapi.someip.deployment for interface +org.genivi.vehicle.playground.Playground { + SomeIpServiceID = 65344 + + attribute consumption { + SomeIpGetterID = 1 + SomeIpNotifierID = 32769 + SomeIpNotifierEventGroups = { + 1 + } + } + + attribute capacity { + SomeIpGetterID = 2 + } + + attribute volume { + SomeIpGetterID = 3 + } + + attribute engineSpeed { + SomeIpGetterID = 4 + SomeIpNotifierID = 32770 + SomeIpNotifierEventGroups = { + 2 + } + } + + attribute currentGear { + SomeIpGetterID = 5 + SomeIpNotifierID = 32771 + SomeIpNotifierEventGroups = { + 3 + } + } + + attribute isReverseGearOn { + SomeIpGetterID = 6 + SomeIpNotifierID = 32772 + SomeIpNotifierEventGroups = { + 4 + } + } + + attribute drivePowerTransmission { + SomeIpGetterID = 7 + SomeIpNotifierID = 32773 + SomeIpNotifierEventGroups = { + 5 + } + } + + attribute doorsOpeningStatus { + SomeIpGetterID = 8 + SomeIpNotifierID = 32774 + SomeIpNotifierEventGroups = { + 6 + } + } + + attribute seatHeatingStatus { + SomeIpGetterID = 9 + SomeIpSetterID = 10 + SomeIpNotifierID = 32775 + SomeIpNotifierEventGroups = { + 7 + } + } + + attribute seatHeatingLevel { + SomeIpGetterID = 11 + SomeIpSetterID = 12 + SomeIpNotifierID = 32776 + SomeIpNotifierEventGroups = { + 8 + } + } + + method initTirePressureCalibration { + SomeIpMethodID = 13 + } + + method changeDoorsState { + SomeIpMethodID = 14 + } + + broadcast vehiclePosition { + SomeIpEventID = 32777 + SomeIpEventGroups = { + 9 + } + } + + broadcast currentTankVolume { + SomeIpEventID = 32778 + SomeIpEventGroups = { + 10 + } + } +} diff --git a/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playground.fidl b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playground.fidl new file mode 100644 index 0000000..abfc1b8 --- /dev/null +++ b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playground.fidl @@ -0,0 +1,118 @@ +/* +* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), +* Author: Alexander Domin (Alexander.Domin@bmw.de) +* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, +* Author: Leonardo Ramos (leo.ramos@profusion.mobi) +* +* SPDX-License-Identifier: MPL-2.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was +* not distributed with this file, You can obtain one at +* http://mozilla.org/MPL/2.0/. +*/ + +package org.genivi.vehicle.playground + import org.genivi.vehicle.playgroundtypes.* from "playgroundTypes.fidl" + interface Playground { + version { + major 1 + minor 0 + } + <** + @description : Current consumption in liters per 100 km + **> + attribute Float consumption readonly + <** + @description : Capacity of the fuel tank in milliliters + Unit: ml + **> + attribute UInt8 capacity readonly noSubscriptions + <** + @description : Current volume of fuel in the tank in liters + **> + attribute Float volume readonly noSubscriptions + <** + @description : Engine speed measured as rotations per minute + **> + attribute UInt16 engineSpeed readonly + <** + @description : Current gear + **> + attribute PlaygroundTypes.Gear currentGear readonly + <** + @description : Is reverse gear selected + **> + attribute Boolean isReverseGearOn readonly + <** + @description : Drive Type + **> + attribute PlaygroundTypes.DriveType drivePowerTransmission readonly + <** + @description : Report the opening status for each door + **> + attribute PlaygroundTypes.DoorsStatus doorsOpeningStatus readonly + <** + @description : Describes the seat heating status set by the user. + index 0 == Driver + index 1 == Co-Driver + index 3 == Passenger in the second row on the Driver side + index 4 == Passenger in the second row on the Middle side + index 5 == Passenger in the second row on the Co-driver side + index 6 == Passenger in the third row on the Driver side + index 7 == Passenger in the third row on the Co-driver side + Just for demo the some SomeIP service will return values for Driver and Co-Driver only + **> + attribute Boolean [] seatHeatingStatus + <** + @description : Describes the seat heating level selected by the user + index 0 == Driver + index 1 == Co-Driver + index 3 == Passenger in the second row on the Driver side + index 4 == Passenger in the second row on the Middle side + index 5 == Passenger in the second row on the Co-driver side + index 6 == Passenger in the third row on the Driver side + index 7 == Passenger in the third row on the Co-driver side + Just for demo the some SomeIP service will return values for Driver and Co-Driver only + **> + attribute UInt8 [] seatHeatingLevel + <** + @description : Trigger tire pressure initialization process + **> + method initTirePressureCalibration { + } + <** + @description : Trigger the change on doors opening state + **> + method changeDoorsState { + in { + <** + @description : Commands for closing or opening the doors. + **> + PlaygroundTypes.CarDoorsCommand commands + } + } + <** + @description : Vehicle position data provided by GPS + **> + broadcast vehiclePosition { + out { + <** + @description : The structure containg the GPS data status informations + **> + PlaygroundTypes.StatusGPS statusGPS + } + } + <** + @description : The current tank volume + **> + broadcast currentTankVolume { + out { + <** + @description : Current tank volume in liters + Unit: l + **> + UInt8 volume + } + } +} diff --git a/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playgroundTypes.fdepl b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playgroundTypes.fdepl new file mode 100644 index 0000000..2202c0f --- /dev/null +++ b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playgroundTypes.fdepl @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), +* Author: Alexander Domin (Alexander.Domin@bmw.de) +* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, +* Author: Leonardo Ramos (leo.ramos@profusion.mobi) +* +* SPDX-License-Identifier: MPL-2.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was +* not distributed with this file, You can obtain one at +* http://mozilla.org/MPL/2.0/. +*/ + +import +"platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-4-SOMEIP_deployment_spec.fdepl" +import "playgroundTypes.fidl" + +define org.genivi.commonapi.someip.deployment for typeCollection +org.genivi.vehicle.playgroundtypes.PlaygroundTypes { + + enumeration Gear { + } + + enumeration DriveType { + } + + struct GPSDate { + } + + struct GPSTime { + } + + struct GPSPosition { + } + + struct StatusGPS { + } + + struct DoorsStatus { + } + + enumeration DoorsID { + } + + enumeration DoorCommand { + } + + struct CarDoorsCommand { + } +} diff --git a/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playgroundTypes.fidl b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playgroundTypes.fidl new file mode 100644 index 0000000..ad9090d --- /dev/null +++ b/hardware/implementations/some_ip_hal/franca/org/genivi/vehicle/playgroundTypes.fidl @@ -0,0 +1,217 @@ +/* +* Copyright (C) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG), +* Author: Alexander Domin (Alexander.Domin@bmw.de) +* Copyright (C) 2021, ProFUSION Sistemas e Soluções LTDA, +* Author: Leonardo Ramos (leo.ramos@profusion.mobi) +* +* SPDX-License-Identifier: MPL-2.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was +* not distributed with this file, You can obtain one at +* http://mozilla.org/MPL/2.0/. +*/ + +package org.genivi.vehicle.playgroundtypes + typeCollection PlaygroundTypes { + <** + @description : The gear enumaration value + **> + enumeration Gear { + <** + @description : The unit is being initialized + **> + UNKNOWN_GEAR = 0 + <** + @description : No gear is selected. + **> + NEUTRAL = 1 + <** + @description : First gear is selected. + **> + FIRST_GEAR = 2 + <** + @description : Second gear is selected. + **> + SECOND_GEAR = 3 + <** + @description : Third gear is selected. + **> + THIRD_GEAR = 4 + <** + @description : Fourth gear is selected. + **> + FOURTH_GEAR = 5 + <** + @description : Fifth gear is selected. + **> + FIFTH_GEAR = 6 + <** + @description : Sixth gear is selected. + **> + SIXTH_GEAR = 7 + <** + @description : The gear sensor is reporting an error + **> + ERROR = 8 + } + + <** + @description : Drive Type, + **> + enumeration DriveType { + <** + @description : Power transmission drive on front axle + **> + FRONT_WHEEL_DRIVE = 1 + <** + @description : Power transmission drive on rear axle + **> + REAR_WHEEL_DRIVE = 2 + <** + @description : Power transmission drive on front and rear axles + **> + ALL_WHEEL_DRIVE = 3 + } + + struct GPSDate { + <** + @description : The current day provided by GPS + **> + UInt8 day + <** + @description : The current month provided by GPS + **> + UInt8 month + <** + @description : The current year provided by GPS + **> + UInt16 year + } + + struct GPSTime { + <** + @description : Time seconds provided by GPS + **> + UInt8 second + <** + @description : Time minutes provided by GPS + **> + UInt8 minute + <** + @description : Time hours provided by GPS + **> + UInt8 hour + } + + struct GPSPosition { + <** + @description : The current latitude coordinates of the vehicle + **> + Double currentLatitude + <** + @description : The current longitude coordinates of the vehicle + **> + Double currentLongitude + <** + @description : The current altitude coordinates of the vehicle + **> + Double currentAltitude + } + + struct StatusGPS { + <** + @description : GPS status date + **> + GPSDate statusGPSDate + <** + @description : GPS status time + **> + GPSTime statusGPSTime + <** + @description : GPS status position + **> + GPSPosition statusfGPSPosition + } + + struct DoorsStatus { + <** + @description : The opening status of the front left door + **> + Boolean frontLeft + <** + @description : The opening status of the front right door + **> + Boolean frontRight + <** + @description : The opening status of the rear left door + **> + Boolean rearLeft + <** + @description : The opening status of the rear right door + **> + Boolean rearRight + } + + <** + @description : The gear enumaration value + **> + enumeration DoorsID { + <** + @description : Front left door + **> + FRONT_LEFT = 0 + <** + @description : Front right door + **> + FRONT_RIGHT = 1 + <** + @description : Rear left door + **> + REAR_LEFT = 2 + <** + @description : Rear right door + **> + REAR_RIGHT = 3 + } + + <** + @description : Command to define the opening state of doors + **> + enumeration DoorCommand { + <** + @description : Command for keeping the current door state + **> + NOTHING = 0 + <** + @description : Command for opening the door + **> + OPEN_DOOR = 1 + <** + @description : Command for closing the door + **> + CLOSE_DOOR = 2 + } + + <** + @description : All the doors opening state for the vehicle + **> + struct CarDoorsCommand { + <** + @description : Front left door command + **> + DoorCommand frontLeftDoor + <** + @description : Front right door command + **> + DoorCommand frontRightDoor + <** + @description : Rear left door command + **> + DoorCommand rearLeftDoor + <** + @description : Rear right door command + **> + DoorCommand rearRightDoor + } +} diff --git a/hardware/interfaces/dummy_car_info_hal/aidl/Android.bp b/hardware/interfaces/dummy_car_info_hal/aidl/Android.bp new file mode 100644 index 0000000..d359972 --- /dev/null +++ b/hardware/interfaces/dummy_car_info_hal/aidl/Android.bp @@ -0,0 +1,19 @@ +package { + default_applicable_licenses: ["hardware_interfaces_license"], +} + +aidl_interface { + name: "profusion.hardware.dummy_car_info_hal", + srcs: ["profusion/hardware/dummy_car_info_hal/*.aidl"], + stability: "vintf", + vendor_available: true, + backend: { + cpp: { + enabled: false, + }, + java: { + sdk_version: "module_current", + }, + }, + owner: "Profusion", +} diff --git a/hardware/interfaces/dummy_car_info_hal/aidl/profusion/hardware/dummy_car_info_hal/CarInfo.aidl b/hardware/interfaces/dummy_car_info_hal/aidl/profusion/hardware/dummy_car_info_hal/CarInfo.aidl new file mode 100644 index 0000000..b248475 --- /dev/null +++ b/hardware/interfaces/dummy_car_info_hal/aidl/profusion/hardware/dummy_car_info_hal/CarInfo.aidl @@ -0,0 +1,8 @@ +package profusion.hardware.dummy_car_info_hal; + +@VintfStability +parcelable CarInfo{ + int velocity; + int gear; + int fuel; +} diff --git a/hardware/interfaces/dummy_car_info_hal/aidl/profusion/hardware/dummy_car_info_hal/IDummyCarInfoHAL.aidl b/hardware/interfaces/dummy_car_info_hal/aidl/profusion/hardware/dummy_car_info_hal/IDummyCarInfoHAL.aidl new file mode 100644 index 0000000..31673d4 --- /dev/null +++ b/hardware/interfaces/dummy_car_info_hal/aidl/profusion/hardware/dummy_car_info_hal/IDummyCarInfoHAL.aidl @@ -0,0 +1,6 @@ +package profusion.hardware.dummy_car_info_hal; + +@VintfStability +interface IDummyCarInfoHAL{ + void getCarInfo(out profusion.hardware.dummy_car_info_hal.CarInfo carInfo); +} diff --git a/packages/services/profusion/dummy-car-info-service/Android.bp b/packages/services/profusion/dummy-car-info-service/Android.bp new file mode 100644 index 0000000..0802db0 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/Android.bp @@ -0,0 +1,91 @@ +android_app { + name: "dummyCarInfoService", + platform_apis: true, + srcs: [ + "src/com/profusion/dummyCarInfo/DummyCarInfoService.java", + "src/com/profusion/dummyCarInfo/IDummyCarInfoService.aidl" + ], + dex_preopt: { + enabled: false, + }, + static_libs: [ + "profusion.hardware.dummy_car_info_hal-V1-java", + ], + certificate: "platform", + vintf_fragments: [ + "dummyCarInfo-service.xml", + ], +} + +prebuilt_etc { + name: "permissions.xml", + + src: "permissions.xml", + sub_dir: "permissions", +} + + +java_sdk_library { + name: "DummyCarInfoManager", + installable: true, + required: ["permissions.xml"], + srcs: [ + "src/com/profusion/dummyCarInfo/DummyCarInfoManager.java", + ], + optimize: { + enabled: false, + }, + static_libs: [ + "dummyCarInfoService", + "profusion.hardware.dummy_car_info_hal-V1-java", + ], +} + +javadoc { + name: "dummyCarInfo-doc", + srcs: [ + "src/com/profusion/dummyCarInfo/DummyCarInfoManager.java", + ] +} + +filegroup { + name: "DummyCarInfoManager.api.public.latest", + srcs: [ + "api/current.txt", + ], +} + +filegroup { + name: "DummyCarInfoManager-removed.api.public.latest", + srcs: [ + "api/removed.txt", + ], +} + +filegroup { + name: "DummyCarInfoManager.api.system.latest", + srcs: [ + "api/system-current.txt", + ], +} + +filegroup { + name: "DummyCarInfoManager-removed.api.system.latest", + srcs: [ + "api/system-removed.txt", + ], +} + +filegroup { + name: "DummyCarInfoManager-incompatibilities.api.public.latest", + srcs: [ + "api/incompatibilities.txt", + ], +} + +filegroup { + name: "DummyCarInfoManager-incompatibilities.api.system.latest", + srcs: [ + "api/system-incompatibilities.txt", + ], +} diff --git a/packages/services/profusion/dummy-car-info-service/Android.mk b/packages/services/profusion/dummy-car-info-service/Android.mk new file mode 100644 index 0000000..2f42ab6 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/Android.mk @@ -0,0 +1 @@ +LOCAL_PATH:= $(call my-dir) diff --git a/packages/services/profusion/dummy-car-info-service/AndroidManifest.xml b/packages/services/profusion/dummy-car-info-service/AndroidManifest.xml new file mode 100644 index 0000000..4dfa6b2 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/packages/services/profusion/dummy-car-info-service/api/current.txt b/packages/services/profusion/dummy-car-info-service/api/current.txt new file mode 100644 index 0000000..62d52f2 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/api/current.txt @@ -0,0 +1,11 @@ +// Signature format: 2.0 +package com.profusion.dummyCarInfo { + + public class DummyCarInfoManager { + ctor public DummyCarInfoManager(android.content.Context); + method public String getCarInfo() throws java.lang.Exception; + method public void unbindService(); + } + +} + diff --git a/packages/services/profusion/dummy-car-info-service/api/incompatibilities.txt b/packages/services/profusion/dummy-car-info-service/api/incompatibilities.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/api/incompatibilities.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/packages/services/profusion/dummy-car-info-service/api/removed.txt b/packages/services/profusion/dummy-car-info-service/api/removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/api/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/packages/services/profusion/dummy-car-info-service/api/system-current.txt b/packages/services/profusion/dummy-car-info-service/api/system-current.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/api/system-current.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/packages/services/profusion/dummy-car-info-service/api/system-incompatibilities.txt b/packages/services/profusion/dummy-car-info-service/api/system-incompatibilities.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/api/system-incompatibilities.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/packages/services/profusion/dummy-car-info-service/api/system-removed.txt b/packages/services/profusion/dummy-car-info-service/api/system-removed.txt new file mode 100644 index 0000000..d802177 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/api/system-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.mk b/packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.mk new file mode 100644 index 0000000..ec78bb5 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.mk @@ -0,0 +1,2 @@ +PRODUCT_PACKAGES += dummyCarInfoService +PRODUCT_PACKAGES += DummyCarInfoManager diff --git a/packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.xml b/packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.xml new file mode 100644 index 0000000..7d25a54 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/dummyCarInfo-service.xml @@ -0,0 +1,11 @@ + + + dummyCarInfoService + hwbinder + 1.0 + + IDummyCarInfoService + default + + + diff --git a/packages/services/profusion/dummy-car-info-service/permissions.xml b/packages/services/profusion/dummy-car-info-service/permissions.xml new file mode 100644 index 0000000..b73c456 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/permissions.xml @@ -0,0 +1,4 @@ + + + + diff --git a/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/DummyCarInfoManager.java b/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/DummyCarInfoManager.java new file mode 100644 index 0000000..88776a0 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/DummyCarInfoManager.java @@ -0,0 +1,70 @@ +package com.profusion.dummyCarInfo; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; + +public class DummyCarInfoManager { + private static final String TAG = "DummyCarInfoManager"; + private IDummyCarInfoService dummyCarInfoService; + private Context context; + private boolean isBound = false; + private static final String DUMMY_CAR_SERVICE_PACKAGE = "com.profusion.dummyCarInfo"; + private static final String DUMMY_CAR_SERVICE = "com.profusion.dummyCarInfo.DummyCarInfoService"; + + public DummyCarInfoManager(Context context) { + this.context = context; + bindService(); + } + + private void bindService() { + try { + Intent intent = new Intent(); + intent.setComponent(new ComponentName(DUMMY_CAR_SERVICE_PACKAGE, DUMMY_CAR_SERVICE)); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + Log.e(TAG, "Exception while binding to DummyCarInfoService", e); + } + } + + public void unbindService() { + if (isBound) { + context.unbindService(serviceConnection); + isBound = false; + } + } + + private ServiceConnection serviceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + dummyCarInfoService = IDummyCarInfoService.Stub.asInterface(service); + isBound = true; + Log.d(TAG, "DummyCarInfoService connected"); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + dummyCarInfoService = null; + isBound = false; + Log.d(TAG, "DummyCarInfoService disconnected"); + } + }; + + public String getCarInfo() throws Exception { + if (dummyCarInfoService != null) { + String carInfo = dummyCarInfoService.getCarInfo(); + if (carInfo != null) { + return carInfo; + } else { + Log.e(TAG, "Failed to get car info from DummyCarInfoService"); + throw new Exception("Failed to get car info from DummyCarInfoService"); + } + } else { + Log.e(TAG, "DummyCarInfoService is not bound"); + throw new Exception("DummyCarInfoService is not bound"); + } + } +} diff --git a/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/DummyCarInfoService.java b/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/DummyCarInfoService.java new file mode 100644 index 0000000..be62837 --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/DummyCarInfoService.java @@ -0,0 +1,81 @@ +package com.profusion.dummyCarInfo; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.os.ServiceManager; +import android.util.Log; +import profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL; +import profusion.hardware.dummy_car_info_hal.CarInfo; + +public class DummyCarInfoService extends Service { + private static final String TAG = "DummyCarInfoService"; + + private IDummyCarInfoHAL halService; + private IDummyCarInfoService.Stub binder; + + @Override + public void onCreate() { + super.onCreate(); + Log.d(TAG, "onCreate"); + try { + IBinder binder = ServiceManager.getService("profusion.hardware.dummy_car_info_hal.IDummyCarInfoHAL/default"); + if (binder == null) { + Log.e(TAG, "Failed to get DummyCarInfoHAL from ServiceManager"); + return; + } + halService = IDummyCarInfoHAL.Stub.asInterface(binder); + if (halService == null) { + Log.e(TAG, "Failed to get DummyCarInfoHAL service"); + return; + } + Log.d(TAG, "HAL binded"); + } catch (Exception e) { + Log.e(TAG, "Exception on HAL bind", e); + } + } + + @Override + public IBinder onBind(Intent intent) { + Log.d(TAG, "DummyCarInfoService onBind"); + if (binder == null) { + binder = new DummyCarInfoServiceImpl(); + } + return binder; + } + + private class DummyCarInfoServiceImpl extends IDummyCarInfoService.Stub { + + public DummyCarInfoServiceImpl() { + } + + public String getCarInfo() { + try { + return getCarInfoFromHAL(); + } catch (Exception e) { + Log.e(TAG, "Exception while getting car info from HAL", e); + return null; + } + } + } + + private String getCarInfoFromHAL() throws Exception { + Log.d(TAG, "Getting car info from HAL"); + if (halService != null) { + try { + CarInfo carInfo = new CarInfo(); + halService.getCarInfo(carInfo); + Log.d(TAG, "Car info received from HAL"); + return "Velocity: " + carInfo.velocity + ", Fuel: " + carInfo.fuel + ", Gear: " + carInfo.gear; + } catch (Exception e) { + Log.e(TAG, "Exception on getCarInfo", e); + throw new Exception("Failed to get car info from HAL", e); + } + } else { + Log.e(TAG, "HAL service is not initialized"); + throw new Exception("HAL service is not initialized"); + } + } +} diff --git a/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/IDummyCarInfoService.aidl b/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/IDummyCarInfoService.aidl new file mode 100644 index 0000000..800f5bb --- /dev/null +++ b/packages/services/profusion/dummy-car-info-service/src/com/profusion/dummyCarInfo/IDummyCarInfoService.aidl @@ -0,0 +1,5 @@ +package com.profusion.dummyCarInfo; + +interface IDummyCarInfoService { + String getCarInfo(); +}