在调试Android驱动中,有时会遇到无法使用adb的情况,如果能通过U盘的热插拔能运行shell命令,就可解决adb无法使用的困境。
基本思路是是安装一个驱动,该驱动负责监测usb的插拔事件,然后通过异步通知发给上层的应用,应用通过读取u盘中的脚本,通过system运行脚本里面的函数。
驱动文件如下
#include
#include
#include
#define DEVICE_NAME "usbupdate"
static struct fasync_struct *usbupdate_async_queue;
static struct miscdevice usbupdate_dev;
int usbupdate_open(struct inode *node, struct file *filp)
{
return 0;
}
int usbupdate_fasync(int fd, struct file *filp, int mode)
{
return fasync_helper(fd, filp, mode, &usbupdate_async_queue);
}
int usbupdate_release(struct inode *node, struct file *filp)
{
usbupdate_fasync(-1, filp, 0);
return 0;
}
static struct file_operations usbupdate_dev_fops={
.owner = THIS_MODULE,
.open = usbupdate_open,
.fasync = usbupdate_fasync,
.release = usbupdate_release,
};
static struct miscdevice usbupdate_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &usbupdate_dev_fops,
};
static int usbupdate_notify(struct notifier_block *self, unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
printk("usb device add\n");
kill_fasync(&usbupdate_async_queue, SIGIO, POLL_IN);
break;
case USB_DEVICE_REMOVE:
printk("usb device remove\n");
break;
}
return NOTIFY_OK;
}
static struct notifier_block usbupdate_nb = {
.notifier_call =usbupdate_notify,
};
static int __init update_init(void)
{
int ret;
usb_register_notify(&usbupdate_nb);
ret = misc_register(&usbupdate_dev);
printk("%s\n",__func__);
return ret;
}
static void __exit update_exit(void)
{
misc_deregister(&usbupdate_dev);
printk("%s\n",__func__);
}
module_init(update_init);
module_exit(update_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("www");
应用层的文件为update.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_POINT "/dev/usbupdate"
#define LOG_TAG "usbupdate"
#define filename "/mnt/udisk/update.sh" //升级脚本的路径,不同机型的u盘挂载路径不同,需根据机型修改
int usb_update_state=0;
int fd;
int status;
void systemstatus(int status){
if (-1 == status) {
SLOGE("system error!");
}
else {
SLOGE("exit status value = [0x%x]\n", status);
if (WIFEXITED(status)){
if (0 == WEXITSTATUS(status)){
SLOGE("run shell script successfully.\n");
}
else{
SLOGE("run shell script fail, script exit code: %d\n", WEXITSTATUS(status));
}
}
else{
SLOGE("exit status = [%d]\n", WEXITSTATUS(status));
}
}
}
int read_file(void)
{
FILE *fp;
char str[1024];
char *buf;
buf=(char *)malloc(1024);
if(buf==NULL){
SLOGE("malloc memory err\n");
return -1;
}
SLOGE("malloc memory ok\n");
fp=fopen(filename,"r");
if(fp==NULL){
SLOGE("open err!\n");
return -1;
}
SLOGE("open ok!\n");
while(!feof(fp)){
if(fgets(str,1024,fp)==NULL)
break;
SLOGE("the msg is %s and the length is %d %d\n",str,strlen(str),sizeof(str));
status=system(str);
systemstatus(status);
}
fclose(fp);
return 0;
}
void sig_handler(int sig)
{
SLOGE("%s\n", __FUNCTION__);
read_file();
usb_update_state=1;
}
void open_usb_update_point(void)
{
int f_flags;
fd=open(DEVICE_POINT, O_RDWR);
if(fd < 0){
SLOGE("open");
return;
}
signal(SIGIO, sig_handler);
fcntl(fd, F_SETOWN, getpid());
f_flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, FASYNC | f_flags);
}
int main(int argc,char **argv)
{
open_usb_update_point();
while(1){
sleep(1);
// if(usb_update_state)
// break;
}
SLOGE("usb update finish\n");
close(fd);
return 0;
}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE := update
LOCAL_SRC_FILES := $(call all-subdir-c-files)
include $(BUILD_EXECUTABLE)
在Android源码的根路径,source build/envsetup.sh,lunch选择具体机型,通过mmm -B 应用程序路径编译该应用程序成可执行文件,并丢进/system/bin/。
在init.rc通过如下服务启动update服务,由于需要可执行权限,需要在前面加上
chmod 0777 /system/bin/update
service loaddriver /system/bin/update
class main
user root
group root
oneshot
当然,还必须保证驱动在该服务起来之前加载,否则该服务会由于打开节点错误而退出。
然后将升级脚本拷贝到u盘,接上u盘,就可运行u盘上的脚本了。升级脚本示例如下
mount -o remount /system
touch /system/dddd
mkdir /system/gggg
insmod /system/wwww.ko
cp /system/update.ko /system/
reboot