diff options
author | Tor Lillqvist <tlillqvist@suse.com> | 2011-11-30 21:39:18 +0200 |
---|---|---|
committer | Tor Lillqvist <tlillqvist@suse.com> | 2011-11-30 21:52:52 +0200 |
commit | 5510127e89d6971a219ce3664e4631d6c6dda2b1 (patch) | |
tree | 7e2d7d06892e086700d5b6bddc8a3ec99c476f6b /android/Bootstrap/src | |
parent | a7fe1a0a088b2d3d68e3fc4b0d3e8d5a34f3e203 (diff) |
Android code refactorig and hacking
Sorry for the large unstructured commit. But hey, the Android code is
experimental so far.
Extract the native lo-bootstrap code into a fairly normal library
built in sal. (Previously it was the JNI part of the "Bootstrap" app.)
Just linkink normally to liblo-bootstrap from C++ code that uses it
works fine, no need to do a dlsym lookup.
Bootstrap is still a subclass of NativeActivity and can thus still be
used as an "app" (to start unit tests, or whatever), but can also be
used from some other app's Java code to just get access to the
lo-bootstrap native methods.
Introduce a new top-level "module", android, for Bootstrap and the
experiments with DocumentLoader.
Note that the experimental DocumentLoader app still crashes. It can't
create the com.sun.star.frame.Desktop instance.
I spent lots of time debugging in the painfully inadequate
ndk-gdb. (Even the newer gdb build from the "mingw-and-ndk" project is
quite crappy in many ways.) I should really experiment with
corresponding code on a normal platform first before even trying on
Android. Basically, I think that if I just can get the concept of Java
code that instantiates and uses LO components *in-process* working on
a normal desktop platform, it should work on Android, too.
Diffstat (limited to 'android/Bootstrap/src')
-rw-r--r-- | android/Bootstrap/src/fi/iki/tml/CommandLine.java | 176 | ||||
-rw-r--r-- | android/Bootstrap/src/org/libreoffice/android/Bootstrap.java | 172 |
2 files changed, 348 insertions, 0 deletions
diff --git a/android/Bootstrap/src/fi/iki/tml/CommandLine.java b/android/Bootstrap/src/fi/iki/tml/CommandLine.java new file mode 100644 index 000000000000..fb5adec2acf5 --- /dev/null +++ b/android/Bootstrap/src/fi/iki/tml/CommandLine.java @@ -0,0 +1,176 @@ +// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +// Copyright (C) 2011 Tor Lillqvist <tml@iki.fi> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +package fi.iki.tml; + +import java.util.*; + +public class CommandLine + implements Iterable<String> +{ + private String commandLine; + + public class Tokenizer + implements Iterator<String> + { + private int index = 0; + private String savedNext = null; + + public Tokenizer() + { + } + + public boolean hasNext() + { + if (savedNext != null) + return true; + try { + savedNext = next(); + return true; + } + catch (NoSuchElementException e) { + } + return false; + } + + public String next() + { + if (savedNext != null) { + String result = savedNext; + savedNext = null; + return result; + } + + StringBuffer sb = new StringBuffer(commandLine.length()); + + while (index < commandLine.length() && + commandLine.charAt(index) == ' ') + index++; + + if (index == commandLine.length()) + throw new NoSuchElementException(); + + while (index < commandLine.length() && + commandLine.charAt(index) != ' ') { + char c = commandLine.charAt(index); + if (c == '\'') { + index++; + while (index < commandLine.length() && + commandLine.charAt(index) != '\'') { + sb.append(commandLine.charAt(index)); + index++; + } + } else if (c == '"') { + index++; + while (index < commandLine.length() && + commandLine.charAt(index) != '\"') { + if (commandLine.charAt(index) == '\\') { + index++; + if (index < commandLine.length()) + sb.append(commandLine.charAt(index)); + } else { + sb.append(commandLine.charAt(index)); + } + index++; + } + } else if (c == '\\') { + index++; + if (index < commandLine.length()) + sb.append(commandLine.charAt(index)); + } else { + sb.append(c); + } + index++; + } + return sb.toString(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public Iterator<String> iterator() + { + return new Tokenizer(); + } + + public CommandLine(String commandLine) + { + this.commandLine = commandLine; + } + + public String[] split() + { + ArrayList<String> argv = new ArrayList<String>(10); + + try { + for (String s : this) + argv.add(s); + } + catch (NoSuchElementException e) { + } + + return argv.toArray(new String[0]); + } + + public static String[] split(String commandLine) + { + return new CommandLine(commandLine).split(); + } + + public static void main(String[] args) + { + class Test + { + Test(String commandLine) + { + String[] argv = split(commandLine); + System.out.println("Split of " + commandLine + ":"); + int n = 0; + for (String s : argv) { + System.out.println("argv[" + n + "}: length " + s.length() + ": \"" + s + "\""); + n++; + } + } + } + + new Test(""); + new Test(" "); + new Test(" "); + new Test(" '' "); + new Test("abc def"); + new Test("abc '' def"); + new Test("abc \"\" def"); + new Test(" abc def "); + new Test(" abc def "); + new Test("abc\" \"def"); + new Test("abc\" \"def \"gh\\i\\\" jkl\""); + new Test("abc' def' '\\ghi jkl'"); + } +} + +// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java b/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java new file mode 100644 index 000000000000..46ce235d3ad4 --- /dev/null +++ b/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java @@ -0,0 +1,172 @@ +// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +// Version: MPL 1.1 / GPLv3+ / LGPLv3+ +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (the "License"); you may not use this file except in compliance with +// the License or as specified alternatively below. You may obtain a copy of +// the License at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// Major Contributor(s): +// Copyright (C) 2011 Tor Lillqvist <tml@iki.fi> (initial developer) +// Copyright (C) 2011 SUSE Linux http://suse.com (initial developer's employer) +// +// All Rights Reserved. +// +// For minor contributions see the git repository. +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 3 or later (the "GPLv3+"), or +// the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), +// in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable +// instead of those above. + +package org.libreoffice.android; + +import android.app.Activity; +import android.app.NativeActivity; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.util.Log; + +import fi.iki.tml.CommandLine; + +// We override NativeActivity so that we can get at the intent of the +// activity and its extra parameters, that we use to tell us what +// actual LibreOffice "program" to run. I.e. something that on desktop +// OSes would be a program, but for Androis is actually built as a +// shared object, with an "lo_main" function. + +public class Bootstrap extends NativeActivity +{ + private static String TAG = "lo-bootstrap"; + + private static native boolean setup(String dataDir, + String apkFile, + String[] ld_library_path); + + public static native boolean setup(int lo_main_ptr, + Object lo_main_argument, + int lo_main_delay); + + // This is not just a wrapper for the C library dlopen(), but also + // loads recursively dependent libraries. + public static native int dlopen(String library); + + // This is just a wrapper for the C library dlsym(). + public static native int dlsym(int handle, String symbol); + + // To be called after you are sure libgnustl_shared.so + // has been loaded + public static native void patch_libgnustl_shared(); + + // Wrapper for getpid() + public static native int getpid(); + + // Wrapper for system() + public static native void system(String cmdline); + + // Wrapper for putenv() + public static native void putenv(String string); + + public static void setup(Activity activity) + { + String dataDir = null; + + ApplicationInfo ai = activity.getApplicationInfo(); + dataDir = ai.dataDir; + Log.i(TAG, String.format("dataDir=%s\n", dataDir)); + + String llp = System.getenv("LD_LIBRARY_PATH"); + if (llp == null) + llp = "/vendor/lib:/system/lib"; + + String[] llpa = llp.split(":"); + + if (!setup(dataDir, activity.getApplication().getPackageResourcePath(), llpa)) + return; + + } + + @Override + protected void onCreate(Bundle savedInstanceState) + { + setup(this); + + String mainLibrary = getIntent().getStringExtra("lo-main-library"); + + if (mainLibrary == null) + mainLibrary = "libcppunittester"; + + mainLibrary += ".so"; + + Log.i(TAG, String.format("mainLibrary=%s", mainLibrary)); + + // Get "command line" to pass to the LO "program" + String cmdLine = getIntent().getStringExtra("lo-main-cmdline"); + + if (cmdLine == null) + cmdLine = "/data/data/org.libreoffice.android/lib/libqa_sal_types.so"; + + // argv[0] will be replaced by android_main() in lo-bootstrap.c by the + // pathname of the mainLibrary. + cmdLine = "dummy-program-name " + cmdLine; + + Log.i(TAG, String.format("cmdLine=%s", cmdLine)); + + String[] argv = CommandLine.split(cmdLine); + + // Load the LO "program" here and look up lo_main + int loLib = dlopen(mainLibrary); + + if (loLib == 0) { + Log.i(TAG, String.format("Could not load %s", mainLibrary)); + return; + } + + int lo_main = dlsym(loLib, "lo_main"); + if (lo_main == 0) { + Log.i(TAG, String.format("No lo_main in %s", mainLibrary)); + return; + } + + // Tell lo-bootstrap to Start a strace on itself if requested + String strace_args = getIntent().getStringExtra("lo-strace"); + if (strace_args != null) + system("/system/xbin/strace -p " + getpid() + " " + (strace_args != "yes" ? strace_args : "" ) + " &"); + + int delay = 0; + String sdelay = getIntent().getStringExtra("lo-main-delay"); + if (sdelay != null) + delay = Integer.parseInt(sdelay); + + // Tell lo-bootstrap.c the stuff it needs to know + if (!setup(lo_main, argv, delay)) + return; + + // Finally, call our super-class, NativeActivity's onCreate(), + // which eventually calls the ANativeActivity_onCreate() in + // android_native_app_glue.c, which starts a thread in which + // android_main() from lo-bootstrap.c is called. + + // android_main() calls the lo_main() defined in sal/main.h + // through the function pointer passed to setup() above, with + // the argc and argv also saved from the setup() call. + super.onCreate(savedInstanceState); + } + + // This is used to load the 'lo-bootstrap' library on application + // startup. The library has already been unpacked into + // /data/data/<app name>/lib/liblo-bootstrap.so at installation + // time by the package manager. + static { + System.loadLibrary("lo-bootstrap"); + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |