在和别人合作开发的时候,往往存在一方提供库供另一方调用。这个过程存在编译依赖问题,库更新问题。为了解耦,这里可以使用dlopen的方式去使用动态库。
示例如下:
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <pthread.h>
#include "abupdate.h"
typedef int (*FuncptrType)(st_update_progress *);
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
const char getopt_str[] = "xz:y::";
static struct option long_options[] =
{
{"update", optional_argument, 0, 'a'},
{"mask", optional_argument, 0, 'b'},
{"switch_boot_slot", no_argument, 0, 'c'},
{"cancel_switch_boot_slot", no_argument, 0, 'd'},
{"set_current_slot_success", no_argument, 0, 'e'},
{"rollback", no_argument, 0, 'f'},
{"get_boot_slot", no_argument, 0, 'g'},
{"help", no_argument, 0, 'h'},
};
static int usage(void)
{
printf("usage:\n");
printf(" abupdate_app --help\n");
printf(" abupdate_app --update=/data/update.zip --mask=0xff\n");
printf(" abupdate_app --switch_boot_slot\n");
printf(" abupdate_app --cancel_switch_boot_slot\n");
printf(" abupdate_app --set_current_slot_success\n");
printf(" abupdate_app --rollback\n");
printf(" abupdate_app --get_boot_slot\n");
return 0;
}
// 此函数是一个回调函数,用于提供给底层库反馈升级进度
static int progress_callback(st_update_progress update_progress)
{
printf("rollback total: %d%% soc: %d%% mcu:%d%% camera:%d%%\n", update_progress.total, update_progress.soc, update_progress.mcu, update_progress.camera);
return 0;
}
// 此函数主动调用获取升级进度的接口
static int thread_get_progress(void *arg)
{
int ret = 0;
st_update_progress update_progress;
FuncptrType ge_progress_func = NULL;
ge_progress_func = (FuncptrType)arg;
while(1)
{
ret = ge_progress_func(&update_progress);
if(ret == 0)
{
printf("total: %d%% soc: %d%% mcu:%d%% camera:%d%%\n", update_progress.total, update_progress.soc, update_progress.mcu, update_progress.camera);
}
else
{
printf("get progress error.\n");
}
sleep(1);
}
return 0;
}
int main(int argc, char *argv[])
{
int ret = 0;
int opt = 0;
int longindex = 0;
int cmd = 0;
char update_path[256] = {0};
int upgrade_mask = 0;
pthread_t thread_progress;
void *handle = NULL;
int (*update_func)(char *, progress_call_back_pointer, int);
int (*ge_progress_func)(st_update_progress *);
int (*switch_boot_slot_func)(void);
int (*cancel_switch_boot_slot_func)(void);
int (*set_current_slot_success_func)(void);
int (*rollback_func)(void);
int (*cancel_update_func)(void);
int (*get_boot_slot_func)(void);
while((opt = getopt_long(argc, argv, getopt_str, long_options, &longindex)) != -1)
{
switch(opt)
{
case 'a':
memset(update_path, 0, sizeof(update_path));
snprintf(update_path, sizeof(update_path), "%s", optarg);
cmd = 'a';
printf("update_path:%s\n", update_path);
break;
case 'b':
upgrade_mask = strtol(optarg, NULL, 16);
cmd = 'b';
printf("upgrade_mask:0x%x\n", upgrade_mask);
break;
case 'c':
cmd = 'c';
printf("switch_boot_slot.\n");
break;
case 'd':
cmd = 'd';
printf("cancel_switch_boot_slot.\n");
break;
case 'e':
cmd = 'e';
printf("set_current_slot_success.\n");
break;
case 'f':
cmd = 'f';
printf("rollback.\n");
break;
case 'g':
cmd = 'g';
printf("get_boot_slot.\n");
break;
case 'h':
usage();
return 0;
default:
printf("cmd is error.\n");
usage();
return -1;
}
}
handle = dlopen("libabupdate.so", RTLD_LAZY);
if (handle == NULL)
{
printf("dlerror:%s\n", dlerror());
return -1;
}
dlerror();
if(cmd == 'a' || cmd == 'b')
{
if(strlen(update_path) != 0 && upgrade_mask != 0)
{
update_func = dlsym(handle, "ab_update");
if(update_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ge_progress_func = dlsym(handle, "ab_get_progress");
if(ge_progress_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ret = pthread_create(&thread_progress, NULL, thread_get_progress, ge_progress_func);
ret = update_func(update_path, progress_callback, upgrade_mask);
if(ret != 0)
{
printf("ab_update failed\n");
dlclose(handle);
return -1;
}
pthread_cancel(thread_progress);
printf("ab_update success\n");
}
}
else if(cmd == 'c')
{
switch_boot_slot_func = dlsym(handle, "ab_switch_boot_slot");
if(switch_boot_slot_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ret = switch_boot_slot_func();
if(ret != 0)
{
printf("switch_boot_slot failed\n");
dlclose(handle);
return -1;
}
printf("switch_boot_slot success\n");
}
else if(cmd == 'd')
{
cancel_switch_boot_slot_func = dlsym(handle, "ab_cancel_switch_boot_slot");
if(cancel_switch_boot_slot_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ret = cancel_switch_boot_slot_func();
if(ret != 0)
{
printf("cancel_switch_boot_slot failed\n");
dlclose(handle);
return -1;
}
printf("cancel_switch_boot_slot success\n");
}
else if(cmd == 'e')
{
set_current_slot_success_func = dlsym(handle, "ab_set_current_slot_success");
if(set_current_slot_success_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ret = set_current_slot_success_func();
if(ret != 0)
{
printf("set_current_slot_success failed\n");
dlclose(handle);
return -1;
}
printf("set_current_slot_success success\n");
}
else if(cmd == 'f')
{
rollback_func = dlsym(handle, "ab_rollback");
if(rollback_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ret = rollback_func();
if(ret != 0)
{
printf("rollback failed\n");
dlclose(handle);
return -1;
}
printf("rollback success\n");
}
else if(cmd == 'g')
{
get_boot_slot_func = dlsym(handle, "ab_get_boot_slot");
if(get_boot_slot_func == NULL)
{
printf("dlerror:%s\n", dlerror());
dlclose(handle);
return -1;
}
ret = get_boot_slot_func();
if(ret != 0)
{
printf("get_boot_slot failed\n");
dlclose(handle);
return -1;
}
printf("get_boot_slot success\n");
}
else
{
usage();
return -1;
}
return 0;
}
/**
* ./abupdate_app update.zip mask
*/
#if 0
int main(int argc, char *argv[])
{
int upgrade_mask = 0;
int ret = 0;
if (argc != 3)
{
usage();
return -1;
}
upgrade_mask = strtol(argv[2], NULL, 16);
ret = ab_update(argv[1], progress_callback, upgrade_mask);
if (ret != 0)
{
printf("ab_update failed\n");
return -1;
}
return 0;
}
#endif