README.Android | 27 ++++---- sal/android/lo-bootstrap.c | 121 +++++++++++++++++++++++++++++++------- sal/osl/unx/file.cxx | 2 sal/osl/unx/file_misc.cxx | 104 +++++++++++++++++++++++++------- sal/osl/unx/uunxapi.cxx | 32 +++++++++- solenv/inc/unxandr/lo-bootstrap.h | 2 6 files changed, 229 insertions(+), 59 deletions(-)
New commits: commit 90b141496018201ee9df721b382cd2b177a3a92f Author: Tor Lillqvist <[email protected]> Date: Wed Jan 4 00:03:18 2012 +0200 Use the lo_apk_* functions for files under /assets diff --git a/sal/osl/unx/file_misc.cxx b/sal/osl/unx/file_misc.cxx index e1da32a..7c84086 100644 --- a/sal/osl/unx/file_misc.cxx +++ b/sal/osl/unx/file_misc.cxx @@ -53,6 +53,10 @@ #include <algorithm> +#ifdef ANDROID +#include <lo-bootstrap.h> +#endif + /************************************************************************ * ToDo * @@ -70,6 +74,15 @@ typedef struct { rtl_uString* ustrPath; /* holds native directory path */ DIR* pDirStruct; +#ifdef ANDROID + enum Kind + { + KIND_DIRENT = 1, + KIND_ASSETS = 2 + }; + int eKind; + lo_apk_dir* pApkDirStruct; +#endif } oslDirectoryImpl; DirectoryItem_Impl::DirectoryItem_Impl( @@ -169,33 +182,64 @@ oslFileError SAL_CALL osl_openDirectory(rtl_uString* ustrDirectoryURL, oslDirect #endif /* MACOSX */ ) { - /* open directory */ - DIR *pdir = opendir( path ); - - if( pdir ) +#ifdef ANDROID + if( strncmp( path, "/assets/", sizeof( "/assets/" ) - 1) == 0 ) { - /* create and initialize impl structure */ - oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) ); - - if( pDirImpl ) - { - pDirImpl->pDirStruct = pdir; - pDirImpl->ustrPath = ustrSystemPath; + lo_apk_dir *pdir = lo_apk_opendir( path ); - *pDirectory = (oslDirectory) pDirImpl; - return osl_File_E_None; - } - else + if( pdir ) { - errno = ENOMEM; - closedir( pdir ); + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) ); + + if( pDirImpl ) + { + pDirImpl->eKind = oslDirectoryImpl::KIND_ASSETS; + pDirImpl->pApkDirStruct = pdir; + pDirImpl->ustrPath = ustrSystemPath; + + *pDirectory = (oslDirectory) pDirImpl; + return osl_File_E_None; + } + else + { + errno = ENOMEM; + lo_apk_closedir( pdir ); + } } } else +#endif { + /* open directory */ + DIR *pdir = opendir( path ); + + if( pdir ) + { + /* create and initialize impl structure */ + oslDirectoryImpl* pDirImpl = (oslDirectoryImpl*) rtl_allocateMemory( sizeof(oslDirectoryImpl) ); + + if( pDirImpl ) + { + pDirImpl->pDirStruct = pdir; + pDirImpl->ustrPath = ustrSystemPath; +#ifdef ANDROID + pDirImpl->eKind = oslDirectoryImpl::KIND_DIRENT; +#endif + *pDirectory = (oslDirectory) pDirImpl; + return osl_File_E_None; + } + else + { + errno = ENOMEM; + closedir( pdir ); + } + } + else + { #ifdef DEBUG_OSL_FILE - perror ("osl_openDirectory"); fprintf (stderr, path); + perror ("osl_openDirectory"); fprintf (stderr, path); #endif + } } } @@ -218,10 +262,17 @@ oslFileError SAL_CALL osl_closeDirectory( oslDirectory Directory ) if( NULL == pDirImpl ) return osl_File_E_INVAL; - /* close directory */ - if( closedir( pDirImpl->pDirStruct ) ) +#ifdef ANDROID + if( pDirImpl->eKind == oslDirectoryImpl::KIND_ASSETS ) + { + if (lo_apk_closedir( pDirImpl->pApkDirStruct )) + err = osl_File_E_IO; + } + else +#endif { - err = oslTranslateFileError(OSL_FET_ERROR, errno); + if( closedir( pDirImpl->pDirStruct ) ) + err = oslTranslateFileError(OSL_FET_ERROR, errno); } /* cleanup members */ @@ -272,7 +323,16 @@ oslFileError SAL_CALL osl_getNextDirectoryItem(oslDirectory Directory, oslDirect if ((NULL == Directory) || (NULL == pItem)) return osl_File_E_INVAL; - pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True); +#ifdef ANDROID + if( pDirImpl->eKind == oslDirectoryImpl::KIND_ASSETS ) + { + pEntry = lo_apk_readdir(pDirImpl->pApkDirStruct); + } + else +#endif + { + pEntry = osl_readdir_impl_(pDirImpl->pDirStruct, sal_True); + } if (NULL == pEntry) return osl_File_E_NOENT; diff --git a/sal/osl/unx/uunxapi.cxx b/sal/osl/unx/uunxapi.cxx index ee3cdeb..3c2067b 100644 --- a/sal/osl/unx/uunxapi.cxx +++ b/sal/osl/unx/uunxapi.cxx @@ -47,6 +47,10 @@ #include <osl/thread.h> #endif + #ifdef ANDROID + #include <lo-bootstrap.h> + #endif + //########################### inline rtl::OString OUStringToOString(const rtl_uString* s) { @@ -80,7 +84,24 @@ int access_u(const rtl_uString* pustrPath, int mode) { #ifndef MACOSX // not MACOSX - return access(OUStringToOString(pustrPath).getStr(), mode); + const char *path = OUStringToOString(pustrPath).getStr(); +#ifdef ANDROID + if (strncmp(path, "/assets", sizeof("/assets")-1) == 0 && + (path[sizeof("/assets")-1] == '\0' || + path[sizeof("/assets")-1] == '/')) + { + struct stat stat; + if (lo_apk_lstat(path, &stat) == -1) + return -1; + if (mode & W_OK) + { + errno = EACCES; + return -1; + } + return 0; + } +#endif + return access(path, mode); #else return access(macxp_resolveAliasAndConvert(pustrPath).getStr(), mode); #endif @@ -114,7 +135,14 @@ int lstat_u(const rtl_uString* pustrPath, struct stat* buf) { #ifndef MACOSX // not MACOSX - return lstat(OUStringToOString(pustrPath).getStr(), buf); + const char *path = OUStringToOString(pustrPath).getStr(); +#ifdef ANDROID + if (strncmp(path, "/assets", sizeof("/assets")-1) == 0 && + (path[sizeof("/assets")-1] == '\0' || + path[sizeof("/assets")-1] == '/')) + return lo_apk_lstat(path, buf); +#endif + return lstat(path, buf); #else return lstat(macxp_resolveAliasAndConvert(pustrPath).getStr(), buf); #endif commit 2717fe35ae7fd35b787b53d291919449d307ea01 Author: Tor Lillqvist <[email protected]> Date: Tue Jan 3 23:58:19 2012 +0200 Use sizeof(s)-1 instead of strlen(s) on string literals diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx index 458554e..bb31902 100644 --- a/sal/osl/unx/file.cxx +++ b/sal/osl/unx/file.cxx @@ -914,7 +914,7 @@ SAL_CALL osl_openFile( rtl_uString* ustrFileURL, oslFileHandle* pHandle, sal_uIn * we should mmap it from the .apk file */ if (!(uFlags & osl_File_OpenFlag_Write) && - strncmp (buffer, "/assets/", strlen ("/assets/")) == 0) + strncmp (buffer, "/assets/", sizeof ("/assets/") - 1) == 0) { void *address; size_t size; commit 7cc28bae3a8aded334f40bf3a5593b5f6067fdd8 Author: Tor Lillqvist <[email protected]> Date: Tue Jan 3 16:33:10 2012 +0200 Fixes for the lo-bootstrap apk element code Fix some off-by-one style errors, add a new lo_apk_lstat() function, and (temporarily) add some debugging logging. diff --git a/sal/android/lo-bootstrap.c b/sal/android/lo-bootstrap.c index 07c1687..7fc171b 100644 --- a/sal/android/lo-bootstrap.c +++ b/sal/android/lo-bootstrap.c @@ -903,13 +903,17 @@ new_dir(const char *folder_path, lo_apk_dir *result; result = malloc(sizeof(*result)); - if (result == NULL) + if (result == NULL) { + LOGE("lo_apk_opendir: Out of memory"); return NULL; + } result->folder_path = strdup(folder_path); result->current_entry = start_entry; result->remaining_entries = remaining_entries; + LOGI("new_dir(%s,%p,%d) = %p", folder_path, start_entry, remaining_entries, result); + return result; } @@ -918,38 +922,43 @@ __attribute__ ((visibility("default"))) lo_apk_dir * lo_apk_opendir(const char *dirname) { + const char *dn = dirname; int count = cdir_entries; struct cdir_entry *entry = cdir_start; - size_t name_size = strlen(dirname); + size_t name_size; - if (*dirname == '/') { - dirname++; - if (!dirname[0]) + if (*dn == '/') { + dn++; + if (!dn[0]) return new_dir("", cdir_start, count); } + name_size = strlen(dn); while (count--) { if (letoh16(entry->filename_size) >= name_size && - !memcmp(entry->data, dirname, name_size) && + !memcmp(entry->data, dn, name_size) && entry->data[name_size] == '/') break; entry = (struct cdir_entry *)((char *)entry + cdir_entry_size(entry)); } if (count >= 0) - return new_dir(dirname, entry, count+1); + return new_dir(dn, entry, count+1); + + LOGI("lo_apk_opendir(%s) = NULL", dirname); return NULL; } static int -path_component_length(const char *path) +path_component_length(const char *path, + const char *path_end) { - const char *slash = strchr(path, '/'); - - if (slash) - return slash - path; + const char *p = path; + while (p < path_end && + *p != '/') + p++; - return strlen(path); + return p - path; } __attribute__ ((visibility("default"))) @@ -959,33 +968,39 @@ lo_apk_readdir(lo_apk_dir *dirp) static struct dirent result; size_t folder_size = strlen(dirp->folder_path); - while (dirp->remaining_entries > 0) { - const char *folder_end = dirp->current_entry->data + folder_size; + while (dirp->remaining_entries-- > 0) { + struct cdir_entry *entry = dirp->current_entry; + const char *folder_end = entry->data + folder_size; int entry_len; - if (letoh16(dirp->current_entry->filename_size) > folder_size && - !memcmp(dirp->current_entry->data, dirp->folder_path, folder_size) && + dirp->current_entry = (struct cdir_entry *)((char *)entry + cdir_entry_size(entry)); + + if (letoh16(entry->filename_size) > folder_size && + !memcmp(entry->data, dirp->folder_path, folder_size) && *folder_end == '/' && - (entry_len = path_component_length(folder_end + 1)) < 256) { + (entry_len = path_component_length(folder_end + 1, entry->data + entry->filename_size)) < 256) { /* Fake an unique inode number; might be used? */ - result.d_ino = cdir_entries - dirp->remaining_entries + 2; + result.d_ino = cdir_entries - dirp->remaining_entries + 1; result.d_off = 0; result.d_reclen = 0; - if (folder_end[entry_len] == '/') + if (folder_end[1 + entry_len] == '/') result.d_type = DT_DIR; else result.d_type = DT_REG; memcpy(result.d_name, folder_end + 1, entry_len); result.d_name[entry_len] = '\0'; + + LOGI("lo_apk_readdir(%p) = %s:%s", dirp, result.d_type == DT_DIR ? "DIR" : "REG", result.d_name); return &result; } - dirp->remaining_entries--; } + LOGI("lo_apk_readdir(%p) = NULL", dirp); + return NULL; } @@ -996,9 +1011,73 @@ lo_apk_closedir(lo_apk_dir *dirp) free(dirp->folder_path); free(dirp); + LOGI("lo_apk_closedir(%p)", dirp); + return 0; } +static int +new_stat(const char *path, + struct stat *statp, + struct cdir_entry *entry, + int mode, + int fake_ino) +{ + memset(statp, 0, sizeof(*statp)); + statp->st_mode = mode | S_IRUSR | S_IRGRP | S_IROTH; + statp->st_nlink = 1; + if (entry != NULL) + statp->st_size = entry->uncompressed_size; + else + statp->st_size = 0; + statp->st_blksize = 512; + if (statp->st_size == 0) + statp->st_blocks = 0; + else + statp->st_blocks = (statp->st_size - 1) / statp->st_blksize + 1; + /* Leave timestamps at zero for now? */ + statp->st_ino = fake_ino; + + LOGI("lo_apk_lstat(%s) = { st_mode=%o, st_size=%lld, st_ino=%lld }", path, statp->st_mode, statp->st_size, statp->st_ino); + + return 0; +} + +__attribute__ ((visibility("default"))) +int +lo_apk_lstat(const char *path, + struct stat *statp) +{ + const char *pn = path; + int count = cdir_entries; + struct cdir_entry *entry = cdir_start; + size_t name_size; + + if (*pn == '/') { + pn++; + if (!pn[0]) + return new_stat(path, statp, NULL, S_IFDIR, 1); + } + + name_size = strlen(pn); + while (count--) { + if (letoh16(entry->filename_size) >= name_size && + !memcmp(entry->data, pn, name_size) && + (letoh16(entry->filename_size) == name_size || entry->data[name_size] == '/')) + break; + entry = (struct cdir_entry *)((char *)entry + cdir_entry_size(entry)); + } + if (count >= 0) { + if (letoh16(entry->filename_size) == name_size) + return new_stat(path, statp, entry, S_IFREG, cdir_entries - count + 1); + else + return new_stat(path, statp, entry, S_IFDIR, cdir_entries - count + 1); + } + + errno = ENOENT; + return -1; +} + __attribute__ ((visibility("default"))) int lo_dlcall_argc_argv(void *function, diff --git a/solenv/inc/unxandr/lo-bootstrap.h b/solenv/inc/unxandr/lo-bootstrap.h index 71a8d13..48b1a5c 100644 --- a/solenv/inc/unxandr/lo-bootstrap.h +++ b/solenv/inc/unxandr/lo-bootstrap.h @@ -58,6 +58,8 @@ struct dirent *lo_apk_readdir(lo_apk_dir *dirp); int lo_apk_closedir(lo_apk_dir *dirp); +int lo_apk_lstat(const char *path, struct stat *statp); + int lo_dlcall_argc_argv(void *function, int argc, const char **argv); commit 05d0bdbb940eb43d8fd70aa782daa9172c7f32ce Author: Tor Lillqvist <[email protected]> Date: Tue Jan 3 15:27:41 2012 +0200 Minor edits diff --git a/README.Android b/README.Android index 076dff2..e58c811 100644 --- a/README.Android +++ b/README.Android @@ -7,15 +7,16 @@ files, so that they run in a sandboxed environment like that of whatever eventual end-user Android apps there will be that use LO code. -Sure, we could quite easily build unit tests as plain Android -executables, push them to the device or emulator with adb and run them -from adb shell, but that would not be a good test as the environment -would be completely different. They would run as root, and not -sandboxed. We have no intent to require LibreOffice code to be used -only on "rooted" devices etc. +Sure, we could quite easily build unit tests as plain Linux +executables (built against the Android libraries, of course, not +GNU/Linux ones), push them to the device or emulator with adb and run +them from adb shell, but that would not be a good test as the +environment such processs run in is completely different from that in +which real end-user apps with GUI etc run. We have no intent to +require LibreOffice code to be used only on "rooted" devices etc. All Android apps are basically Java programs. They run "in" a Dalvik -virtual machine. Yes, you can also have apps where your code is only +virtual machine. Yes, you can also have apps where *your* code is only native code, written in a compiled language like C or C++. But also also such apps are actually started by system-provided Java bootstrapping code (NativeActivity) running in a Dalvik VM. @@ -30,13 +31,13 @@ out how to manually construct an .apk that is properly signed so that it will run in the emulator. (I don't have any Android device...) I only know how to let the SDK Ant tooling do it... -A LO Android app would work would something like this: +At this stage, the plan is that a LO Android app will work would +something like this: -We have a top Java bootstrapping class -org.libreoffice.android.Bootstrap that loads a small helper native -library liblo-bootstrap.so that implements JNI wrappers for dlopen(), -dlsym(), and ELF header scanning coresponding to looking for DT_NEEDED -entries with readelf. +We have a Java class org.libreoffice.android.Bootstrap that that loads +a small helper native library liblo-bootstrap.so that implements JNI +wrappers for dlopen(), dlsym(), and ELF header scanning coresponding +to looking for DT_NEEDED entries with readelf. The Java code then loads the actual native library that corresponds to the LibreOffice-related "program" we want to run. For unit tests, a _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
