一种通过U盘热插拔的升级方法

         在调试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;
}

相应的Android.mk文件如下

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


你可能感兴趣的:(DRIVERS)