Android support (#918)

* Support of alternative layout and basic cmake

* Added ltdl link

* Added open from FD

* Changed behavoir of library... integration of autotools

* Redesign of USB device access, crash fix

* Removed non needed cmake files

* Fixed missing merge
This commit is contained in:
Artyom Beilis
2023-10-24 10:40:15 +03:00
committed by GitHub
parent c1a96bffd8
commit 807d44d0dc
9 changed files with 173 additions and 1 deletions

View File

@@ -198,6 +198,7 @@ int gp_init_localedir (const char *localedir);
*/
#ifdef _GPHOTO2_INTERNAL_CODE
#define CAMLIBDIR_ENV "CAMLIBS"
#define CAMLIBDIR_PREFIX_ENV "CAMLIBS_PREFIX"
#endif /* _GPHOTO2_INTERNAL_CODE */

View File

@@ -179,8 +179,13 @@ foreach_func (const char *filename, lt_ptr data)
{
foreach_data_t *fd = data;
CameraList *list = fd->list;
char *prefix = getenv(CAMLIBDIR_PREFIX_ENV);
GP_LOG_D ("Found '%s'.", filename);
if(prefix && !strstr(filename,prefix)) {
GP_LOG_D("Skipping camlib filename '%s' not matching %s.",filename,prefix);
return (0);
}
fd->result = gp_list_append (list, filename, NULL);
return ((fd->result == GP_OK)?0:1);
@@ -312,6 +317,7 @@ unlocked_gp_abilities_list_load_dir (CameraAbilitiesList *list, const char *dir,
return GP_ERROR_CANCEL;
}
}
gp_context_progress_stop (context, p);
lt_dlexit ();
gp_list_free (flist);

View File

@@ -384,6 +384,10 @@ GP_CHECK_LIBRARY([LIBUSB1],[libusb-1.0],[>= 1.0.0],
AC_DEFINE([HAVE_LIBUSB_STRERROR], [1],
[Define if libusb-1.0 has libusb_strerror])
])
AC_CHECK_FUNC([libusb_wrap_sys_device], [dnl
AC_DEFINE([HAVE_LIBUSB_WRAP_SYS_DEVICE], [1],
[Define if libusb-1.0 has libusb_wrap_sys_device])
])
LIBS="$save_LIBS"
], [],
[default-on],

View File

@@ -106,6 +106,7 @@ int gp_port_init_localedir (const char *localedir);
*/
#ifdef _GPHOTO2_INTERNAL_CODE
#define IOLIBDIR_ENV "IOLIBS"
#define IOLIBDIR_PREFIX_ENV "IOLIBS_PREFIX"
#endif /* _GPHOTO2_INTERNAL_CODE */

View File

@@ -202,6 +202,21 @@ int gp_port_set_pin (GPPort *port, GPPin pin, GPLevel level);
int gp_port_send_break (GPPort *port, int duration);
int gp_port_flush (GPPort *port, int direction);
/**
* \brief Allow using file descriptor of USB device without auto-discovery
*
* This is required for access of USB on android since applications don't have direct
* access to USB device
*
* It must be called prior to library initialization
*/
int gp_port_usb_set_sys_device(int fd);
/**
* \brief Get externally set file descriptor of USB device, return -1 if not set
*/
int gp_port_usb_get_sys_device(void);
int gp_port_usb_find_device (GPPort *port, int idvendor, int idproduct);
int gp_port_usb_find_device_by_class (GPPort *port, int mainclass, int subclass, int protocol);
int gp_port_usb_clear_halt (GPPort *port, int ep);

View File

@@ -238,8 +238,13 @@ foreach_func (const char *filename, lt_ptr data)
GPPortType type;
unsigned int j, old_size = list->count;
int result;
char *prefix = getenv(IOLIBDIR_PREFIX_ENV);
GP_LOG_D ("Called for filename '%s'.", filename );
if(prefix && !strstr(filename,prefix)) {
GP_LOG_D("Skipping filename '%s' not matching %s.",filename,prefix);
return (0);
}
lh = lt_dlopenext (filename);
if (!lh) {

View File

@@ -38,6 +38,7 @@
#include <gphoto2/gphoto2-port-library.h>
#include <gphoto2/gphoto2-port-log.h>
#include <gphoto2/gphoto2-port-locking.h>
#include <gphoto2/gphoto2-port.h>
#include "libgphoto2_port/gphoto2-port-info.h"
@@ -1214,3 +1215,37 @@ gp_port_get_error (GPPort *port)
return _("No error description available");
}
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
static int gp_port_usb_fd = -1;
int
gp_port_usb_set_sys_device(int fd)
{
gp_port_usb_fd = fd;
return (GP_OK);
}
int
gp_port_usb_get_sys_device(void)
{
return gp_port_usb_fd;
}
#else
int gp_port_usb_set_sys_device(int fd)
{
return GP_ERROR_NOT_SUPPORTED;
}
int gp_port_usb_get_sys_device()
{
return -1;
}
#endif

View File

@@ -48,6 +48,8 @@ LIBGPHOTO2_5_0 {
gp_port_timeout_get;
gp_port_timeout_set;
gp_port_usb_clear_halt;
gp_port_usb_set_sys_device;
gp_port_usb_get_sys_device;
gp_port_usb_find_device;
gp_port_usb_find_device_by_class;
gp_port_usb_msg_class_read;

View File

@@ -116,6 +116,33 @@ struct _PrivateIrqCompleted {
/* FIXME: safe size? */
#define INTERRUPT_BUFFER_SIZE 256
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
static struct _GPPortExternalSysDevice {
/* some more may be used in future */
libusb_device_handle *h;
libusb_device *d;
libusb_context *ctx;
libusb_device *dl[1];
} external_sys_device = { NULL, NULL, NULL, { NULL } };
static int has_external_fd()
{
if(gp_port_usb_get_sys_device() == -1)
return 0;
if(external_sys_device.h)
return 1;
libusb_set_option(NULL,LIBUSB_OPTION_NO_DEVICE_DISCOVERY,NULL);
C_LIBUSB (libusb_init (&external_sys_device.ctx), GP_ERROR_IO);
LOG_ON_LIBUSB_E(libusb_wrap_sys_device(external_sys_device.ctx,gp_port_usb_get_sys_device(),&external_sys_device.h));
external_sys_device.d = libusb_get_device(external_sys_device.h);
external_sys_device.dl[0] = external_sys_device.d;
return 1;
}
#endif
struct _GPPortPrivateLibrary {
libusb_context *ctx;
libusb_device *d;
@@ -155,6 +182,10 @@ load_devicelist (GPPortPrivateLibrary *pl) {
time_t xtime;
time(&xtime);
#if HAVE_LIBUSB_WRAP_SYS_DEVICE
if(!has_external_fd()) /* when external device present no need to research for Android */
#endif
{
if (xtime != pl->devslastchecked) {
if (pl->nrofdevs)
libusb_free_device_list (pl->devs, 1);
@@ -163,6 +194,16 @@ load_devicelist (GPPortPrivateLibrary *pl) {
pl->devs = NULL;
pl->descs = NULL;
}
}
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(has_external_fd()) {
pl->nrofdevs = 1;
pl->devs = external_sys_device.dl;
C_MEM (pl->descs = calloc (1, sizeof(pl->descs[0])));
LOG_ON_LIBUSB_E (libusb_get_device_descriptor(pl->devs[0], &pl->descs[0]));
}
#endif
if (!pl->nrofdevs) {
int i;
@@ -186,7 +227,16 @@ gp_port_library_list (GPPortInfoList *list)
int nrofdevs = 0;
struct libusb_device_descriptor *descs;
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(has_external_fd()) {
ctx = external_sys_device.ctx;
}
else {
C_LIBUSB (libusb_init (&ctx), GP_ERROR_IO);
}
#else
C_LIBUSB (libusb_init (&ctx), GP_ERROR_IO);
#endif
/* TODO: make sure libusb_exit gets called in all error paths inside this function */
@@ -197,11 +247,20 @@ gp_port_library_list (GPPortInfoList *list)
gp_port_info_set_path (info, "^usb:");
gp_port_info_list_append (list, info); /* do not check return value, it might be -1 */
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(has_external_fd()) {
nrofdevs = 1;
devs = external_sys_device.dl;
}
else
#endif
{
nrofdevs = libusb_get_device_list (ctx, &devs);
if (!nrofdevs) {
libusb_exit (ctx); /* should free all stuff above */
goto nodevices;
}
}
C_MEM (descs = calloc (nrofdevs, sizeof(descs[0])));
for (i=0;i<nrofdevs;i++)
@@ -309,8 +368,13 @@ gp_port_library_list (GPPortInfoList *list)
C_GP (gp_port_info_list_append (list, info));
}
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(!has_external_fd())
#endif
{
libusb_free_device_list (devs, 1);
libusb_exit (ctx); /* should free all stuff above */
}
free (descs);
nodevices:
@@ -333,11 +397,19 @@ static int gp_libusb1_init (GPPort *port)
port->pl->config = port->pl->interface = port->pl->altsetting = -1;
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(has_external_fd()) {
port->pl->ctx = external_sys_device.ctx;
}
else
#endif
{
if (LOG_ON_LIBUSB_E (libusb_init (&port->pl->ctx))) {
free (port->pl);
port->pl = NULL;
return GP_ERROR_IO;
}
}
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
unlink("usblog.raw");
port->pl->logfd = open("usblog.raw",O_CREAT|O_WRONLY,0644);
@@ -356,9 +428,20 @@ gp_libusb1_exit (GPPort *port)
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (port->pl->logfd >=0 ) close (port->pl->logfd);
#endif
if (port->pl->nrofdevs)
if (port->pl->nrofdevs) {
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(!has_external_fd())
#endif
{
libusb_free_device_list (port->pl->devs, 1);
}
}
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(!has_external_fd())
#endif
{
libusb_exit (port->pl->ctx);
}
free (port->pl);
port->pl = NULL;
}
@@ -380,13 +463,27 @@ gp_libusb1_open (GPPort *port)
C_PARAMS (port->pl->d);
}
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(gp_port_usb_get_sys_device() != -1) {
if(!external_sys_device.h) {
LOG_ON_LIBUSB_E(libusb_wrap_sys_device(port->pl->ctx,gp_port_usb_get_sys_device(),&external_sys_device.h));
libusb_ref_device(libusb_get_device(external_sys_device.h));
}
port->pl->dh = external_sys_device.h;
port->pl->d = libusb_get_device(external_sys_device.h);
}
else
#endif
{
C_LIBUSB (libusb_open (port->pl->d, &port->pl->dh), GP_ERROR_IO);
}
if (!port->pl->dh) {
int saved_errno = errno;
gp_port_set_error (port, _("Could not open USB device (%s)."),
strerror(saved_errno));
return GP_ERROR_IO;
}
ret = libusb_kernel_driver_active (port->pl->dh, port->settings.usb.interface);
#if 0
@@ -493,6 +590,9 @@ gp_libusb1_close (GPPort *port)
_close_async_interrupts(port);
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
if(gp_port_usb_get_sys_device() == -1) {
#endif
if (libusb_release_interface (port->pl->dh,
port->settings.usb.interface) < 0) {
int saved_errno = errno;
@@ -523,6 +623,9 @@ gp_libusb1_close (GPPort *port)
}
libusb_close (port->pl->dh);
#ifdef HAVE_LIBUSB_WRAP_SYS_DEVICE
}
#endif
struct _PrivateIrqCompleted *irq_iter;
struct _PrivateIrqCompleted *irq_next;