尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Android的自启动

Android的自启动 最近要用到这个所以也花时间看看。从分层来说安卓的自启动也分成三种app的自启动framework服务的自启动HAL服务的自启动。现在简单说说这三种吧。当然我主要关注的还是最后一种。。。一 App的自启动1 AndroidManifest.xml中修改uses-permission android:nameandroid.permission.RECEIVE_BOOT_COMPLETED /2 编写广播接收器public class BootCompletedReceiver extends BroadcastReceiver { Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { // 启动应用的主活动 Intent activityIntent new Intent(context, MainActivity.class); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(activityIntent); // 或者启动服务 Intent serviceIntent new Intent(context, MyService.class); context.startService(serviceIntent); } } }3 在AndroidManifest.xml中注册广播接收器receiver android:name.BootCompletedReceiver android:enabledtrue android:exportedfalse intent-filter action android:nameandroid.intent.action.BOOT_COMPLETED / category android:nameandroid.intent.category.DEFAULT / /intent-filter /receiver二 Framework的自启动基本上和app差不多有一些细微修改。AndroidManifest.xml中定义是这样的。service android:name.MyService android:enabledtrue android:exportedfalse /在广播接收器中启动服务是这样的。Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { Intent serviceIntent new Intent(context, MyService.class); context.startService(serviceIntent); } }三 Hal service的自启动1 增加service.rcservice SampleService /system/bin/sampleservice class hal user system group system # 如果在rc⽂件中添加了 class hal即归类为hal服务会在init的start hal阶段通过 hwservice启动所有的hal服务。在Android.bp中增加这个rc文件。2 增加Selinux权限关于这部分可以看看我之前写的SEAndroid学习12 -- SELinux-CSDN博客关于这个部分有两个部分是一个系统的配置一个是服务的配置。系统配置在瑞芯微的平台是这样获取路径的get_build_var BOARD_SEPOLICY_DIRShwservice.tetype vnd_nxpnfc_hwservice, hwservice_manager_type;hwservice_contextsvendor.nxp.nxpnfc::INxpNfc (对照manifest中增加的instance别写错) u:object_r:vnd_nxpnfc_hwservice:s0file_contexts/vendor/bin/hw/vendor\.nxp\.nxpnfc1\.0-service u:object_r:nxpnfc_hal_exec:s0服务配置fileservice.tetype nxpnfc_hal, domain; type nxpnfc_hal_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(nxpnfc_hal) add_hwservice(nfc, vnd_nxpnfc_hwservice) # 如果是通过nfc进程启动新加的服务才需要添 加具体可以参考这个android 实现一个开机自启动的service_android开机自启动service-CSDN博客下周会具体做部分工作到时候再更新把。。。参考Rockchip_Developer_Guide_Android_SELinux(Sepolicy)_CN.pdf我在 Ask 模式下无法执行命令去翻代码但启动列表的方式是 Android 平台通用的标准机制我直接给你梳理清楚。你的板子是 Android 系统平台 neo61所以**核心就是 init 进程的 .rc 启动脚本**。## 方法一标准做法修改 init.rc 添加 serviceAndroid 启动的核心是 /system/bin/init它读取编译进 ramdisk/system 的 .rc 文件来拉起所有服务。要加入自启动程序在某个 .rc 文件里加一个 service 段rcservice hello /system/bin/helloclass mainuser rootgroup rootseclabel u:r:su:s0 # 或你程序对应的 sepolicy domainoneshot然后1. 把编译好的 hello 放到 /system/bin/或 /vendor/bin/2. 在 device/vendor/neo61/init.rc或平台默认 init.rc / init.usb.rc 等里加入上面的 service3. class main 让它在开机 main class 阶段被拉起**.rc 文件在代码里的位置**Android 源码树不是 kernel_platformdevice/vendor/board/init.rcdevice/vendor/board/init.recovery.rcsystem/core/rootdir/init.rc # 通用框架vendor/... /init*.rc # 厂商自定义## 方法二临时验证用不用改代码靠 adb 直接注册如果你只是想开机自动跑而不重新编译整个系统可以这样bashadb rootadb remount # 让 /system 可写userdebug/eng 版本才行adb push hello /system/bin/helloadb shell chmod 755 /system/bin/helloadb shell echo service hello /system/bin/helloclass late_startoneshot /vendor/etc/init/hello.rcadb reboot/vendor/etc/init/ 目录下的所有 .rc 会被 init 自动加载这是厂商扩展服务的标准目录**不需要重新编译系统**只要文件系统可写就行。## 方法三内核态你的 kernel 代码最相关如果你想要的是**内核模块随开机加载**比如指纹/SPI 驱动那种那走的是另一套机制- 把驱动编进内核在 [Kconfig](home/jc/kernel/kernel/kernel_platform/msm-kernel/drivers/input/fingerprint/goodix) 相关位置加配置CONFIG_XXXy- 或者编成 .ko 模块在 .rc 里用 insmod或放到 /vendor/lib/modules/ 配合 modprobe- 指纹驱动这类通常有自己的 .rc比如 fpsensor.rc里注册 service## 关键注意事项1. **SELinux**Android 强制 SELinux新加的 service 如果 seclabel / domain 配置不对会被直接拒绝avc: denied。eng/userdebug 可先 setenforce 0 测试。2. **二进制路径**/system/bin 编译进去的和 adb push 进去的是两种流程。3. **oneshot 标志**hello 是一次性程序必须加 oneshot否则 init 会认为它崩溃并反复重启。## 结合你的情况推荐你这个 hello乃至 SPI POC 程序最合适的接法是- **临时测试** → 方法二adb push /vendor/etc/init/xxx.rc最快- **正式集成** → 方法一在源码树里加 service 编译进 system image你的 SPI POC 如果最终要随开机自启去验证硬件建议用**方法二**先跑通确认稳定后再落进源码。需要我切到 Code 模式帮你把具体某个 .rc 文件找出来看看现有 service 怎么写的随时说。四 临时验证不改镜像最快如果只是想测试自启动而不重编整个系统userdebug/eng 版本可 adb remountadb root adb remount adb push hello /vendor/bin/hello adb shell chmod 755 /vendor/bin/hello # 在 /vendor/etc/init/ 下新建一个 rcinit 会自动加载该目录下所有 .rc adb shell echo service hello /vendor/bin/hello class late_start oneshot /vendor/etc/init/hello.rc adb reboot重启后 hello 就会自动跑。这也验证了为什么不重编镜像也能加自启动。实测有点问题原因是在我验证的板子上板子的 adb remount使用 verlayfs。init 在系统启动早期扫描 /vendor/etc/init 时没有加载后来通过 overlay 新增的 .rc因此 hello_script 服务没有被注册。最后看了在板子上原本有配置/vendor/etc/init/hw/init.qcom.rc。service qti-testscripts /system/bin/sh /product/etc/init.qcom.testscripts.sh class late_start user root disabled oneshot seclabel u:r:qti-testscripts:s0 on property:sys.boot_completed1 start qti-testscripts每次系统启动完成后init 都会以 root 身份运行。所以直接修改/product/etc/init.qcom.testscripts.sh这个脚本也可以。创建一个hello.sh#!/system/bin/sh now$(date %Y-%m-%d %H:%M:%S) messagehello init startup: ${now}, pid$$, boot_completed$(getprop sys.boot_completed) /system/bin/log -t hello_init $message echo $message /data/local/tmp/hello-startup.log推送这个脚本 $adb push .\hello.sh /vendor/bin/hello.sh $adb shell chmod 0755 /vendor/bin/hello.sh $adb shell restorecon /vendor/bin/hello.sh手动验证 $adb shell /system/bin/sh /vendor/bin/hello.sh $adb shell cat /data/local/tmp/hello-startup.log $adb shell logcat -d -s hello_init:I *:S在init.qcom.testscripts.sh文件末尾增加# Local board startup hook installed for bring-up testing. if [ -f /vendor/bin/hello.sh ]; then /system/bin/sh /vendor/bin/hello.sh fi只通过init验证 $adb shell start qti-testscripts $adb shell cat /data/local/tmp/hello-startup.log在“没有完整源码、只有系统镜像、SDK 又不完全匹配”的条件下能力边界很明确自己的 App通常可以增加。Native 常驻服务可以增加适合作为 HAL 的替代方案。标准 HAL Service有条件可以但难度明显更高。修改或新增 Framework Service理论上能逆向修改实际非常不推荐。如果需要稳定量产最终仍应向板卡厂商索取匹配当前固件的 BSP、签名密钥和编译环境。最现实的架构建议先不要直接修改 Framework也不要一开始就把 native 服务包装成正式 HAL系统/priv-app │ Binder、Socket、JNI ▼ 自己的 Native Daemon │ ▼ 设备节点、串口、GPIO、I²C、厂商库这样在没有源码时最容易部署和维护App 负责界面和 Android 生命周期。Native daemon 负责底层硬件和常驻运行。两者通过 Unix socket、Binder、AIDL或 JNI 通信。使用现有qti-testscripts启动 daemon或者最终修改真实镜像中的 init rc。1. 增加自己的 App普通 App如果不需要系统权限直接安装adb install -r .\MyApp.apk开机运行后台逻辑App 注册BOOT_COMPLETED。如果要显示界面也可以调试阶段从现有启动脚本调用/system/bin/am start -n com.example.myapp/.MainActivity但 Android 14 会限制后台启动 Activity 和后台 Service因此最好使用BOOT_COMPLETEDJobScheduler前台服务Device Owner/Kiosk 模式预装系统 App可以先尝试推入/product/app/product/app/MyApp/MyApp.apk需要特权权限则放/product/priv-app/MyApp/MyApp.apk同时需要匹配的权限白名单例如/product/etc/permissions/privapp-permissions-myapp.xml示例permissions privapp-permissions packagecom.example.myapp permission nameandroid.permission.WRITE_SECURE_SETTINGS/ /privapp-permissions /permissions不过要注意放进priv-app不等于自动获得所有权限。部分权限要求 platform 签名。没有厂商 platform 签名密钥就无法正常获得signature权限。Android 14 对 priv-app 白名单校验比较严格。overlayfs 新文件在部分启动阶段可能不可见需要重新打包真实镜像。因此首先应确认 APK 需要哪些权限再判断普通安装、预装、priv-app 或 platform 签名哪一种可行。SDK 不最新的问题只要编译 App 使用的compileSdk足够高并设置适合板子的android { compileSdk 34 defaultConfig { minSdk 适当版本 targetSdk 34 } }通常不需要板厂完整源码。App 主要依赖公开 Android SDK。如果要调用板厂私有 API则需要从镜像中提取相关 JAR或通过反射调用这种方式兼容性差。2. 增加 Native 常驻服务这是没有源码时最值得采用的方案。交叉编译 ARM64 可执行文件然后部署/vendor/bin/mydaemon测试阶段可以继续通过现有入口启动if [ -x /vendor/bin/mydaemon ]; then /vendor/bin/mydaemon \ /data/vendor/mydaemon.log 21 fi更稳妥的是把 daemon 放到/data/vendor/...或/product/bin/...取决于它需要访问哪些库和资源。需要检查file mydaemon readelf -d mydaemon板子是arm64-v8a Android 14建议尽量静态链接自己的第三方依赖但不要尝试完全静态链接 Android/Bionic 系统组件。长期运行时还要处理进程崩溃重启日志轮转文件权限设备节点权限SELinux32/64 位 ABI厂商共享库依赖当前 SELinux 为Permissive开发验证容易正式切回Enforcing后必须增加策略否则可能无法工作。3. 增加真正的 HAL Service这取决于你是否真的需要让 Android Framework 通过标准 HAL 接口访问它。可能实现的部分即使没有完整源码也可以自行准备ARM64 HAL 可执行程序AIDL/HIDL 接口库init rcVINTF manifest fragmentSELinux policy客户端 App或 native client对于 AIDL HAL大致需要/vendor/bin/hw/vendor.example.hardware.demo-service /vendor/etc/init/vendor.example.hardware.demo-service.rc /vendor/etc/vintf/manifest/vendor.example.hardware.demo.xml /vendor/etc/selinux/...但存在几个现实障碍新增 rc 当前不能通过 overlayfs 被 early init 加载。新增 VINTF fragment 是否在启动时被看到也有类似风险。没有对应 vendor sepolicy 编译环境很难增加正确的 domain。VINTF 兼容性检查可能阻止错误的 manifest。AIDL/HIDL 生成代码必须与板子实际 Binder/NDK 接口兼容。如果 Framework 没有对应客户端HAL 启动后也无人使用。因此要做正式 HAL至少需要重新打包并刷入真实的vendor.img而不是仅靠adb push。没有 Framework 配合时如果 HAL 只服务于自己的 App没有必要强行做系统 HAL。可以改成App → Binder/Unix Socket → Native daemon这比修改 VINTF、SELinux 和 Framework 简单得多。如果自己的 App 是普通应用不能直接访问 vendor BinderUnix domain socket 或本地 TCP socket通常更容易但同样要设计身份认证和权限限制。4. 增加 Framework Service这是当前条件下最困难的一项。真正的 Framework Service 通常运行在system_server需要修改frameworks/base增加 AIDL修改SystemServer注册 Binder service增加service_contexts修改 SELinux可能修改framework.jar、services.jar重新生成 oat/vdex 或让系统重新优化使用匹配的构建工具和依赖保持与当前 ROM 完全一致没有匹配源码时只能考虑反编译services.jar framework.jar boot-framework*.art/oat/vdex然后修改 smali、重新打包和处理 dexpreopt。风险包括系统卡在开机动画system_server循环崩溃API/字段与旧 SDK 不匹配签名或校验失败OTA 后完全失效难以调试和回滚所以不建议通过 smali 修改 Framework 来做产品功能。可替代方案如果目标只是“拥有较高权限、开机常驻、向其他组件提供接口”优先选择priv-app Android Service或者native daemon 自己的 App如果需要其他 App 调用可在自己的系统 App 中提供exported bound serviceAIDL Binder ServiceContentProviderBroadcastReceiverSocket API这些都不要求修改system_server。5. 镜像层面怎么修改由于当前 overlayfs 对新增 init rc 有启动可见性问题正式部署需要离线修改镜像。典型流程是提取固件 → 解包 super.img → 提取 product.img/vendor.img/system_ext.img → 解开 ext4 或 EROFS 镜像 → 加入 APK、daemon、rc、VINTF 配置 → 修正权限、UID/GID、SELinux xattr/file_contexts → 重新生成镜像 → 重新打包 super.img → fastboot/烧录工具刷入但开始之前必须确认adb shell getprop ro.boot.dynamic_partitions adb shell getprop ro.build.ab_update adb shell getprop ro.boot.slot_suffix adb shell mount adb shell cat /proc/filesystems还需要确认各分区是ext4EROFS动态分区A/B 分区AVB 签名是否有足够分区空间AVB 已经在当前板子上被adb disable-verity禁用开发阶段会容易一些但重新打包镜像仍要保证尺寸、super metadata 和刷写流程正确。推荐推进顺序基于目前这块板子我建议先做普通 App验证功能和公开 API。需要系统权限时再尝试 productpriv-app和权限白名单。底层硬件访问做成 ARM64 native daemon。开发阶段使用已验证的qti-testscripts启动 daemon。App 与 daemon 通过受权限控制的 socket/AIDL 通信。功能稳定后离线重打product.img/vendor.img。只有标准兼容性明确要求时才升级为正式 HAL。不修改 Framework确实必须修改时向板厂索要匹配 Android 14 固件的 BSP 和 platform 签名密钥。最适合当前条件的最终形态是预装 App ↕ 自定义 IPC ↕ Native daemon ↕ 硬件它可以覆盖大多数“App HAL Framework 扩展”想解决的业务需求同时不依赖完整 Android 源码。
返回列表