# vsomeip-android-service **Repository Path**: daileyet/vsomeip-android-service ## Basic Information - **Project Name**: vsomeip-android-service - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-04 - **Last Updated**: 2026-06-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vSOMEIP Android 项目 基于 vSOMEIP (3.1.37.1) 的 Android NDK 集成项目,采用源码交叉编译 + 前台 Service 架构。 ## 项目结构 ``` vsomeip-android/ ├── scripts/ # 编译脚本 │ ├── 01_build_boost.sh # Boost 1.71.0 交叉编译(boost-cmake) │ ├── 02_build_vsomeip.sh # vSOMEIP 交叉编译(COVESA 官方源码) │ └── 03_copy_libs.sh # 复制库和头文件到 jniLibs ├── third_party/ # 第三方依赖源码和编译输出(不提交到Git) │ ├── boost-cmake/ # boost-cmake 仓库 │ ├── boost-1.71/ # Boost 编译输出 │ ├── vsomeip/ # vSOMEIP 官方源码 │ └── vsomeip-android/ # vSOMEIP 编译输出 ├── android-project/ # Android Studio 项目 │ └── app/ │ ├── src/main/ │ │ ├── aidl/ # AIDL 接口定义 │ │ │ └── com/openthinks/someip/ │ │ │ ├── ISomeIPService.aidl │ │ │ └── ISomeIPCallback.aidl │ │ ├── cpp/ # JNI C++ 源码 │ │ ├── java/ # Java 源码 │ │ │ └── com/openthinks/someip/ │ │ │ ├── MainActivity.java │ │ │ ├── SomeIPManager.java │ │ │ ├── SomeIPService.java │ │ │ ├── SomeIPClient.java │ │ │ └── service/ │ │ │ ├── SomeIPForegroundService.java │ │ │ ├── SomeIPServiceImpl.java │ │ │ ├── ServerImpl.java │ │ │ └── ClientImpl.java │ │ ├── jniLibs/ # 预编译原生库(由脚本生成,不提交到Git) │ │ ├── assets/ # vSOMEIP 配置文件 │ │ └── res/ # Android 资源文件 │ └── build.gradle.kts └── README.md # 本文档 ``` ## 环境要求 | 组件 | 版本 | |------|------| | Android NDK | r30 (30.0.14904198) | | Boost | 1.71.0 | | vSOMEIP | 3.1.37.1 (官方 COVESA 仓库) | | 目标架构 | arm64-v8a, x86_64 | | API Level | 21 (编译) / 29+ (运行) | | C++ 标准 | C++11 (编译) / C++17 (Android 项目) | | CMake | 3.22.1+ | | JDK | 17+ | ## 快速开始 ### 1. 编译 Boost ```bash cd /xxx/vsomeip-android ./scripts/01_build_boost.sh ``` - 使用 boost-cmake 自动下载 Boost 1.71.0 源码 - 自动应用 Boost.Thread future.hpp 补丁(NDK r30 Clang 兼容性) - 输出到 `third_party/boost-1.71/{arm64-v8a,x86_64}/` ### 2. 编译 vSOMEIP ```bash ./scripts/02_build_vsomeip.sh ``` - 从 COVESA 官方仓库克隆 vSOMEIP 源码 - 自动切换到 3.1.37.1(该版本 CMakeLists.txt 已有完善的 Android 支持,无需补丁) - 输出到 `third_party/vsomeip-android/{arm64-v8a,x86_64}/` ### 3. 复制库和头文件到项目 ```bash ./scripts/03_copy_libs.sh ``` 复制以下内容到 `android-project/app/src/main/jniLibs/`: - vSOMEIP 共享库:`libvsomeip3.so`, `libvsomeip3-cfg.so`, `libvsomeip3-sd.so`, `libvsomeip3-e2e.so` - Boost 静态库:`libboost_system.a`, `libboost_thread.a`, `libboost_filesystem.a` - 头文件:`include/vsomeip/` ### 4. 编译 APK ```bash cd android-project export JAVA_HOME=/path/to/jdk-17 export ANDROID_SDK_ROOT=/path/to/android/sdk ./gradlew :app:assembleDebug ``` ### 5. 安装到设备/模拟器 ```bash $ANDROID_SDK_ROOT/platform-tools/adb install -r app/build/outputs/apk/debug/SomeipNDKService.apk ``` ## 架构设计 ### 前台 Service + AIDL 架构 ``` ┌─────────────────────────────────────────┐ │ Activity (UI 层) │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ bindService │──│ ISomeIPService │ │ │ │ (显式Intent)│ │ (AIDL 接口) │ │ │ └─────────────┘ └─────────────────┘ │ └─────────────────────────────────────────┘ │ ▼ (同一进程,Binder 直接调用) ┌─────────────────────────────────────────┐ │ SomeIPForegroundService │ │ ┌─────────────────────────────────┐ │ │ │ onCreate: startForeground() │ │ │ │ ├─ init clientManager │ │ │ │ │ └─ auto start client loop │ │ │ │ ├─ init serverManager (idle) │ │ │ │ │ └─ server 按需启动 │ │ │ │ └─ start reconnection watchdog │ │ │ │ │ │ │ │ ISomeIPService.Stub 实现: │ │ │ │ ├─ startServer() │ │ │ │ ├─ stopServer() │ │ │ │ ├─ connectClient() │ │ │ │ ├─ disconnectClient() │ │ │ │ ├─ sendClientRequest() │ │ │ │ ├─ sendServerResponse() │ │ │ │ ├─ registerCallback() │ │ │ │ └─ ... │ │ │ └─────────────────────────────────┘ │ └─────────────────────────────────────────┘ ``` ### 内部实现分层 ``` ISomeIPService.aidl (单一 AIDL 接口) │ ▼ SomeIPServiceImpl.java (Stub 薄封装) │ ┌───┴───┐ ▼ ▼ ServerImpl ClientImpl (纯业务逻辑) (纯业务逻辑 + 自动重连) │ │ ▼ ▼ SomeIPManager SomeIPManager + SomeIPService + SomeIPClient ``` - **SomeIPServiceImpl**: AIDL 线程安全、参数校验、异常捕获、转发到 Impl - **ServerImpl**: 管理 Server 生命周期、服务发布、请求处理 - **ClientImpl**: 管理 Client 生命周期、自动重连(5秒间隔)、服务发现 ## AIDL 接口 ### ISomeIPService.aidl ```aidl package com.openthinks.someip; import com.openthinks.someip.ISomeIPCallback; interface ISomeIPService { // Server control (按需启动) boolean startServer(int serviceId, int instanceId, int majorVersion, int minorVersion); boolean stopServer(int serviceId, int instanceId); boolean registerServerMessageHandler(int serviceId, int instanceId, int methodId); boolean sendServerResponse(int serviceId, int instanceId, int methodId, in byte[] payload, long requestId); // Client control (Service 启动时默认自动连接) boolean connectClient(int serviceId, int instanceId); boolean disconnectClient(int serviceId, int instanceId); boolean sendClientRequest(int serviceId, int instanceId, int methodId, in byte[] payload); boolean subscribeEvent(int serviceId, int instanceId, int eventId, int eventGroupId); boolean unsubscribeEvent(int serviceId, int instanceId, int eventId); // Callback registration void registerCallback(ISomeIPCallback callback); void unregisterCallback(ISomeIPCallback callback); // Lifecycle / status boolean isServerRunning(int serviceId, int instanceId); boolean isClientConnected(int serviceId, int instanceId); void shutdown(); } ``` ### ISomeIPCallback.aidl ```aidl package com.openthinks.someip; oneway interface ISomeIPCallback { void onMessageReceived(int serviceId, int instanceId, int methodId, in byte[] payload, long requestId); void onServiceAvailable(int serviceId, int instanceId, boolean available); void onServerRequest(int serviceId, int instanceId, int methodId, in byte[] payload, long requestId); void onError(String operation, String error); } ``` ## Activity 使用示例 ```java public class MainActivity extends AppCompatActivity { private ISomeIPService someIPService; private final Handler mainHandler = new Handler(Looper.getMainLooper()); private final ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { someIPService = ISomeIPService.Stub.asInterface(service); try { someIPService.registerCallback(callback); // Service 已默认启动 Client,Activity 只需检查状态 boolean connected = someIPService.isClientConnected(0x1234, 0x5678); } catch (RemoteException e) { Log.e(TAG, "Service setup failed", e); } } @Override public void onServiceDisconnected(ComponentName name) { someIPService = null; } }; private final ISomeIPCallback callback = new ISomeIPCallback.Stub() { @Override public void onMessageReceived(int serviceId, int instanceId, int methodId, byte[] payload, long requestId) { mainHandler.post(() -> { // 处理收到的消息 }); } @Override public void onServiceAvailable(int serviceId, int instanceId, boolean available) { mainHandler.post(() -> { // 更新服务可用性 UI }); } @Override public void onServerRequest(int serviceId, int instanceId, int methodId, byte[] payload, long requestId) { mainHandler.post(() -> { // 处理服务端收到的请求,发送响应 try { someIPService.sendServerResponse(serviceId, instanceId, methodId, payload, requestId); } catch (RemoteException e) { Log.e(TAG, "Send response failed", e); } }); } @Override public void onError(String operation, String error) { mainHandler.post(() -> { // 显示错误 }); } }; @Override protected void onStart() { super.onStart(); Intent intent = new Intent(this, SomeIPForegroundService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if (someIPService != null) { try { someIPService.unregisterCallback(callback); } catch (RemoteException e) { Log.e(TAG, "unregisterCallback failed", e); } } unbindService(connection); } // 启动服务端 private void startServer() { new Thread(() -> { try { boolean ok = someIPService.startServer(0x1234, 0x5678, 1, 0); if (ok) { someIPService.registerServerMessageHandler(0x1234, 0x5678, 0x0421); } } catch (RemoteException e) { Log.e(TAG, "startServer failed", e); } }).start(); } // 连接客户端 private void connectClient() { new Thread(() -> { try { boolean ok = someIPService.connectClient(0x1234, 0x5678); } catch (RemoteException e) { Log.e(TAG, "connectClient failed", e); } }).start(); } // 发送请求 private void sendRequest() { new Thread(() -> { try { byte[] payload = "Hello vSOMEIP".getBytes(); boolean ok = someIPService.sendClientRequest(0x1234, 0x5678, 0x0421, payload); } catch (RemoteException e) { Log.e(TAG, "sendClientRequest failed", e); } }).start(); } } ``` ## 关键配置说明 ### build.gradle.kts ```kotlin android { ndkVersion = "30.0.14904198" minSdk = 29 ndk { abiFilters += listOf("arm64-v8a", "x86_64") } externalNativeBuild { cmake { cppFlags += listOf("-std=c++17", "-frtti", "-fexceptions") arguments += listOf("-DANDROID_STL=c++_shared", "-DANDROID_PLATFORM=android-29") } } buildFeatures { aidl = true } } ``` ### CMakeLists.txt ```cmake # 导入 vSOMEIP 共享库 add_library(vsomeip3 SHARED IMPORTED) set_target_properties(vsomeip3 PROPERTIES IMPORTED_LOCATION ${VSOMEIP_LIB_DIR}/libvsomeip3.so) # 导入 Boost 静态库 add_library(boost_system STATIC IMPORTED) set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION ${VSOMEIP_LIB_DIR}/libboost_system.a) # 链接 target_link_libraries(someip_jni vsomeip3 vsomeip3-cfg vsomeip3-sd vsomeip3-e2e boost_system boost_thread boost_filesystem ${log-lib}) ``` ### AndroidManifest.xml ```xml ``` ## 库加载顺序 `SomeIPManager` 静态代码块中按以下顺序加载: ```java System.loadLibrary("c++_shared"); System.loadLibrary("vsomeip3"); System.loadLibrary("vsomeip3-cfg"); System.loadLibrary("vsomeip3-sd"); System.loadLibrary("vsomeip3-e2e"); System.loadLibrary("someip_jni"); ``` ## 自动重连机制 ClientImpl 内部实现自动重连: - **检查间隔**: 5 秒 - **触发条件**: Client 断开连接(`!client.isServiceAvailable()`) - **重连动作**: `disconnect()` + `connect(10000)` - **结果通知**: 通过 `ISomeIPCallback.onServiceAvailable` 通知 Activity - **停止条件**: Service 销毁时 `reconnectEnabled.set(false)` 并 `shutdownNow()` ## 注意事项 1. `vsomeip.json` 中的 `applications.name` 必须与 `nativeCreateApplication()` 参数一致 2. `VSOMEIP_BASE_PATH` 必须指向应用私有目录(代码中已自动设置为 `context.getCacheDir()/vsomeip/`) 3. 一个系统只能有一个 Routing Manager 4. `jniLibs/` 下的所有文件由脚本生成,**不要提交到 Git** 5. 编译脚本依赖环境变量 `ANDROID_NDK_HOME`、`ANDROID_SDK_ROOT` 或 `ANDROID_HOME` 6. **前台 Service**: Android 8+ 必须使用前台 Service 长期运行,状态栏会显示通知 7. **AIDL 回调线程**: 回调在 Binder 线程池执行,更新 UI 需切回主线程(使用 `Handler`) ## 已知问题 ### 运行时崩溃排查 如果应用启动时崩溃,请检查: 1. **库加载顺序**:必须按 `c++_shared` -> `vsomeip3` -> `vsomeip3-cfg` -> `vsomeip3-sd` -> `vsomeip3-e2e` -> `someip_jni` 的顺序加载 2. **配置文件路径**:`VSOMEIP_CONFIGURATION` 必须指向有效的 vsomeip.json 3. **VSOMEIP_BASE_PATH**:必须指向可写的应用私有目录 4. **ABI 一致性**:确保 jniLibs 中的库与设备架构匹配 ### 版本兼容性 - vSOMEIP 3.1.37.1 使用旧版 Boost.Asio API(`io_service::work`),与 Boost 1.71 兼容 - 不要升级到新版本 vSOMEIP 或 Boost 1.84,会导致运行时崩溃 ## 待优化项 1. **合并编译脚本**:将三个脚本合并为单个 `build_all.sh` 2. **增量编译**:添加增量编译支持,避免每次全量编译 3. **CI/CD 支持**:添加 GitHub Actions 或 GitLab CI 流水线 4. **废弃 API**: - `SomeIPClient.sendRequest()` — 已废弃,推荐 `ClientImpl.sendRequestAsync()` - `SomeIPClient.sendRequestAsync()` — 已废弃,推荐 `ClientImpl.sendRequestAsync()` - `ClientImpl.sendRequest()` — 已废弃,推荐 `ClientImpl.sendRequestAsync()` 5. **文档完善**: - 添加 vsomeip.json 配置指南 - 更多调试和故障排查文档 6. **性能优化**: - 减少 JNI 调用次数 - 优化回调线程模型 > 详细设计见:[Client/Server 业务逻辑实现](doc/06-client-server-impl.md) | [已知问题排查](doc/08-troubleshooting.md)