通过树莓派自启动实现软件远程升级与自动重启

业务背景

在用树莓派做监控设备时,远程控制树莓派是很基本的需求。总体来说包括:

  • 对树莓派本身的控制,比如重启、查看设备状态、修改树莓派配置等。
  • 对业务软件的控制,比如升级、查看软件状态、修改软件配置等。

实现原理

无论是哪一种业务,其基本实现原理都是通用的:通过软件作为命令接收终端进行业务拓展。
实现的方式和技术选型多种多样,不是本篇的重点,本人使用java作为开发语言,使用Netty接收网络命令进行业务处理。(简单提一句,树莓派自带了jdk,对数据库的操作比较友好,能够节省很多时间)
本篇仅考虑软件远程升级这一个业务场景,需要实现的功能包括升级包的接收、组包、存储、升级、重启,前面接收、组包、存储也不是本篇的重点,这里只记录升级和重启这两步在树莓派上的实现方法供以后查阅。

实现方法

软件升级和重启这两步可以有几种方式:

  • 直接调用升级程序对软件进行升级和重启,需要实现升级程序,并且考虑好时序问题
  • 先重启树莓派,然后通过树莓派的自启动功能完成升级和重启功能
    本篇文档采用第二种方式实现

通过java软件重启树莓派

通过在jvm中增加一个关闭的钩子RunTime.getRunTime().addShutdownHook,在关闭前创建一个新的线程调用系统重启命令完成树莓派的重启

1
2
3
4
5
6
7
8
9
10
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
Runtime.getRuntime().exec("reboot");
} catch (IOException e) {
LogHelper.warn("执行reboot异常:" , e);
}
}
});
System.exit(0);

额外说一下,jvm的关闭方式有三种:

  • 正常关闭:当最后一个非守护线程结束或者调用了System.exit或者通过其他特定平台的方法关闭(发送SIGINT,SIGTERM信号等)
  • 强制关闭:通过调用Runtime.halt方法或者是在操作系统中直接kill(发送SIGKILL信号)掉JVM进程
  • 异常关闭:运行中遇到RuntimeException异常等。

配置树莓派自启动

比如以pi用户登录,则在/home/pi/.config中创建autostart文件夹,在文件夹下创建jarstart.desktop文件(文件名可以随意,后缀必须为.desktop) 在文件中输入:

1
2
3
[Desktop Entry]
Exec=sh /home/pi/Downloads/restart.sh
Type=Application

则在树莓派重启之后会自动调用/home/pi/Downloads/restart.sh脚本,然后通过restart.sh脚本实现升级和启动的操作

脚本实现升级和软件启动

比如软件和升级包都放在相同的目录下/home/pi/Downloads,软件名称为App.jar,待升级的软件包叫upgrade.jar,则脚本应该如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Desktop Entry]
#!/bin/sh

cd '/home/pi/Downloads'

myFile="App.jar"
myUpGradeFile="upgrade.jar"

if [ -f "$myUpGradeFile" ]; then
if [ -f "$myFile" ]; then
rm -f "$myFile"
fi
mv "$myUpGradeFile" "$myFile"
fi

if [ -f "$myFile" ]; then
java -jar "$myFile"
fi

此脚本先切换到软件目录,并将升级包替换原来的App.jar软件,然后启动App.jar软件,到此完成整个程序的远程升级和重启。