Skip to content

Commit

Permalink
moved platform dependent code into separate functions
Browse files Browse the repository at this point in the history
support multiple native libraries within a single apk (required for unity)
  • Loading branch information
crowriot committed Jan 13, 2013
1 parent 955950b commit ce2b496
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 85 deletions.
214 changes: 147 additions & 67 deletions apkenv.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ lookup_symbol_impl(const char *method)
return jni_shlib_resolve(&global, method); return jni_shlib_resolve(&global, method);
} }


void *
lookup_lib_symbol_impl(const char *lib, const char *method)
{
return jni_shlib_lib_resolve(&global, lib, method);
}

void void
foreach_file_impl(const char *prefix, apk_for_each_file_callback callback) foreach_file_impl(const char *prefix, apk_for_each_file_callback callback)
{ {
Expand Down Expand Up @@ -295,50 +301,10 @@ operation(const char *operation, const char *filename)


#define MEEGOTOUCH_BORDER 16 #define MEEGOTOUCH_BORDER 16


//#define NOSDL void* platform_data = 0;



int main(int argc, char **argv) SDL_Surface* platform_init()
{ {
char **tmp;

recursive_mkdir(DATA_DIRECTORY_BASE);
global.apkenv_executable = argv[0];
global.apkenv_headline = APKENV_HEADLINE;
global.apkenv_copyright = APKENV_COPYRIGHT;

printf("%s\n%s\n\n", global.apkenv_headline, global.apkenv_copyright);

switch (argc) {
case 2:
/* One argument - the .apk (continue below) */
break;
case 3:
/* Two arguments - operation + the apk */
operation(argv[1], argv[2]);
break;
default:
/* Wrong number of arguments */
usage();
}

global.lookup_symbol = lookup_symbol_impl;
global.foreach_file = foreach_file_impl;
global.read_file = read_file_impl;

jnienv_init(&global);
javavm_init(&global);
global.apk_filename = strdup(argv[argc-1]);
global.apklib_handle = apk_open(global.apk_filename);
global.support_modules = NULL;


const char *shlib = apk_get_shared_library(global.apklib_handle);
if (shlib == NULL) {
printf("Not a native APK.\n");
return 0;
}

SDL_Surface* screen; SDL_Surface* screen;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
printf("SDL Init failed.\n"); printf("SDL Init failed.\n");
Expand All @@ -355,8 +321,12 @@ int main(int argc, char **argv)
**/ **/
#ifdef PANDORA #ifdef PANDORA
screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,0,SDL_FULLSCREEN); screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,0,SDL_FULLSCREEN);
void* gles = GLES_Init(1); #if defined(APKENV_GLES2)
if (!gles) { platform_data = GLES_Init(2);
#else
platform_data = GLES_Init(1);
#endif
if (!platform_data) {
fprintf(stderr,"ERROR: GLES_Init failed.\n"); fprintf(stderr,"ERROR: GLES_Init failed.\n");
return 0; return 0;
} }
Expand Down Expand Up @@ -397,15 +367,115 @@ int main(int argc, char **argv)
XChangeProperty(dpy, wm.info.x11.wmwindow, atom, XA_CARDINAL, 32, XChangeProperty(dpy, wm.info.x11.wmwindow, atom, XA_CARDINAL, 32,
PropModeReplace, (unsigned char*)region, 4); PropModeReplace, (unsigned char*)region, 4);
#endif #endif
return screen;
}

void platform_swap()
{
#ifdef PANDORA
GLES_SwapBuffers(platform_data);
#elif defined(FREMANTLE)
SDL_GLES_SwapBuffers();
#else
SDL_GL_SwapBuffers();
#endif
}

void platform_exit()
{
#ifdef PANDORA
GLES_Exit(platform_data);
#endif
}

int main(int argc, char **argv)
{
char **tmp;


global.method_table = jni_shlib_find_methods(shlib); recursive_mkdir(DATA_DIRECTORY_BASE);
global.jni_library = android_dlopen(shlib, RTLD_LAZY);
unlink(shlib); global.apkenv_executable = argv[0];
if (!(global.jni_library)) { global.apkenv_headline = APKENV_HEADLINE;
printf("Missing library dependencies.\n"); global.apkenv_copyright = APKENV_COPYRIGHT;

printf("%s\n%s\n\n", global.apkenv_headline, global.apkenv_copyright);

switch (argc) {
case 2:
/* One argument - the .apk (continue below) */
break;
case 3:
/* Two arguments - operation + the apk */
operation(argv[1], argv[2]);
break;
default:
/* Wrong number of arguments */
usage();
}

global.lookup_symbol = lookup_symbol_impl;
global.lookup_lib_symbol = lookup_lib_symbol_impl;
global.foreach_file = foreach_file_impl;
global.read_file = read_file_impl;

jnienv_init(&global);
javavm_init(&global);
global.apk_filename = strdup(argv[argc-1]);
global.apklib_handle = apk_open(global.apk_filename);
global.support_modules = NULL;


/*
const char *shlib = apk_get_shared_library(global.apklib_handle,"");
if (shlib == NULL) {
printf("Not a native APK.\n");
return 0;
}
*/
const char* libdir[] = {
"assets/libs/armeabi-v7a",
"assets/libs/armeabi",
"lib/armeabi-v7a",
"lib/armeabi",
0
};
int ilib = 0;
struct SharedLibrary *shlibs = 0;
while (libdir[ilib]!=0) {
shlibs = apk_get_shared_libraries(global.apklib_handle,libdir[ilib]);
if (shlibs!=0)
break;
ilib ++;
}
if (shlibs==0) {
printf("Not a native APK.\n");
return 0; return 0;
} }


struct JniLibrary *lib = malloc(sizeof(struct JniLibrary));
struct JniLibrary *head = lib;
lib->next = 0;

struct SharedLibrary *shlib = shlibs;
while (shlib!=0) {
lib->lib = android_dlopen(shlib->filename,RTLD_LAZY);
if (!(lib->lib)) {
printf("Missing library dependencies.\n");
return 0;
}
lib->method_table = jni_shlib_find_methods(shlib->filename);
lib->name = strdup(shlib->filename);
// unlink(shlib->filename);
shlib = shlib->next;
if (shlib!=0) {
lib->next = malloc(sizeof(struct JniLibrary));
lib = lib->next;
lib->next = 0;
}
}

global.libraries = head;

load_modules("."); load_modules(".");
load_modules(MODULE_DIRECTORY_BASE); load_modules(MODULE_DIRECTORY_BASE);


Expand All @@ -424,14 +494,24 @@ int main(int argc, char **argv)


if (module == NULL) { if (module == NULL) {
printf("Not supported yet, but found JNI methods:\n"); printf("Not supported yet, but found JNI methods:\n");
tmp = global.method_table;
while (*tmp) { struct JniLibrary *lib = global.libraries;
printf(" %s\n", *tmp); while (lib!=0) {
tmp++; tmp = lib->method_table;
while (*tmp) {
printf(" %s\n", *tmp);
tmp++;
}
lib = lib->next;
} }
goto finish; goto finish;
} }


SDL_Surface* screen = platform_init();
if (screen==0) {
return 0;
}

global.active_module = module; global.active_module = module;
printf("Using module: %s\n", module->filename); printf("Using module: %s\n", module->filename);
install_overrides(module); install_overrides(module);
Expand Down Expand Up @@ -482,26 +562,26 @@ int main(int argc, char **argv)
} }
} }
module->update(module); module->update(module);
#ifdef PANDORA
GLES_SwapBuffers(gles); platform_swap();
#elif defined(FREMANTLE)
SDL_GLES_SwapBuffers();
#else
SDL_GL_SwapBuffers();
#endif
} }


finish: finish:
tmp = global.method_table;
while (*tmp) { lib = global.libraries;
free(*tmp++); while (lib!=0) {
tmp = lib->method_table;
while (*tmp) {
free(*tmp++);
}
free(lib->method_table);
struct JniLibrary *next = lib->next;
free(lib);
lib = next;
} }
free(global.method_table);
apk_close(global.apklib_handle); apk_close(global.apklib_handle);


#ifdef PANDORA
GLES_Exit(gles);
#endif


return 0; return 0;
} }
Expand Down
13 changes: 11 additions & 2 deletions apkenv.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -63,9 +63,18 @@ struct SupportModule {
}; };


typedef void *(*lookup_symbol_t)(const char *method); typedef void *(*lookup_symbol_t)(const char *method);
typedef void *(*lookup_lib_symbol_t)(const char *lib, const char *method);
typedef void (*foreach_file_t)(const char *prefix, apk_for_each_file_callback callback); typedef void (*foreach_file_t)(const char *prefix, apk_for_each_file_callback callback);
typedef int (*read_file_t)(const char *filename, char **buffer, size_t *size); typedef int (*read_file_t)(const char *filename, char **buffer, size_t *size);


struct JniLibrary {
struct JniLibrary *next;
char *name;
void *lib;
char **method_table;
};


struct GlobalState { struct GlobalState {
const char *apkenv_executable; const char *apkenv_executable;
const char *apkenv_headline; const char *apkenv_headline;
Expand All @@ -79,13 +88,13 @@ struct GlobalState {
const char *apk_filename; const char *apk_filename;
AndroidApk *apklib_handle; AndroidApk *apklib_handle;


void *jni_library; struct JniLibrary *libraries;
char **method_table;


struct SupportModule *support_modules; struct SupportModule *support_modules;
struct SupportModule *active_module; struct SupportModule *active_module;


lookup_symbol_t lookup_symbol; lookup_symbol_t lookup_symbol;
lookup_lib_symbol_t lookup_lib_symbol;
foreach_file_t foreach_file; foreach_file_t foreach_file;
read_file_t read_file; read_file_t read_file;
}; };
Expand Down
25 changes: 17 additions & 8 deletions apklib/apklib.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -49,27 +49,28 @@ apk_open(const char *filename)
return apk; return apk;
} }


char * struct SharedLibrary*
apk_get_shared_library(AndroidApk *apk) apk_get_shared_libraries(AndroidApk *apk, const char* libdir)
{ {
assert(apk != NULL); assert(apk != NULL);


char filename[PATH_MAX], tmpname[PATH_MAX]; char filename[PATH_MAX], tmpname[PATH_MAX];
FILE *result = NULL; FILE *result = NULL;
char buf[64*1024]; char buf[64*1024];
int read; int read;
struct SharedLibrary *libs = 0;
struct SharedLibrary *head = 0;
int libdirlen = strlen(libdir);


if (unzGoToFirstFile(apk->zip) != UNZ_OK) { if (unzGoToFirstFile(apk->zip) != UNZ_OK) {
return NULL; return NULL;
} }


do { do {
if (unzGetCurrentFileInfo(apk->zip, NULL, filename, sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) { if (unzGetCurrentFileInfo(apk->zip, NULL, filename, sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) {
if (memcmp(filename, "lib/armeabi", 11) == 0) { if (memcmp(filename, libdir, libdirlen) == 0) {
if (unzOpenCurrentFile(apk->zip) == UNZ_OK) { if (unzOpenCurrentFile(apk->zip) == UNZ_OK) {




#if !defined(PANDORA) #if !defined(PANDORA)
strcpy(filename, "/home/user/.apkenv-XXXXXX"); strcpy(filename, "/home/user/.apkenv-XXXXXX");
int fd = mkstemp(filename); int fd = mkstemp(filename);
Expand All @@ -90,14 +91,22 @@ apk_get_shared_library(AndroidApk *apk)
#if defined(PANDORA) #if defined(PANDORA)
sync(); sync();
#endif #endif
return strdup(filename); if (libs==0) {
libs = malloc(sizeof(struct SharedLibrary));
head = libs;
libs->next = 0;
} else {
libs->next = malloc(sizeof(struct SharedLibrary));
libs->next->next = 0;
libs = libs->next;
}
libs->filename = strdup(filename);
} }
break;
} }
} }
} while (unzGoToNextFile(apk->zip) == UNZ_OK); } while (unzGoToNextFile(apk->zip) == UNZ_OK);


return NULL; return head;
} }


enum ApkResult enum ApkResult
Expand Down
7 changes: 6 additions & 1 deletion apklib/apklib.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -42,11 +42,16 @@ enum ApkResult {
APK_ERROR, APK_ERROR,
}; };


struct SharedLibrary {
struct SharedLibrary *next;
char* filename;
};

typedef void (*apk_for_each_file_callback)(const char *filename, char *buffer, size_t size); typedef void (*apk_for_each_file_callback)(const char *filename, char *buffer, size_t size);


/* apklib.c */ /* apklib.c */
AndroidApk *apk_open(const char *filename); AndroidApk *apk_open(const char *filename);
char *apk_get_shared_library(AndroidApk *apk); struct SharedLibrary* apk_get_shared_libraries(AndroidApk *apk, const char *libdir);
enum ApkResult apk_read_file(AndroidApk *apk, const char *filename, char **buffer, size_t *size); enum ApkResult apk_read_file(AndroidApk *apk, const char *filename, char **buffer, size_t *size);
void apk_for_each_file(AndroidApk *apk, const char *prefix, apk_for_each_file_callback callback); void apk_for_each_file(AndroidApk *apk, const char *prefix, apk_for_each_file_callback callback);
void apk_close(AndroidApk *apk); void apk_close(AndroidApk *apk);
Expand Down
Loading

0 comments on commit ce2b496

Please sign in to comment.