Bug 565142 - Support startup on Android, patch by vlad, blassey, alexp, and me. r=dougt
authorMichael Wu <mwu@mozilla.com>
Thu, 03 Jun 2010 18:16:20 -0700
changeset 43080 9065d777cf6215cba066c90915d1a759e5b45f22
parent 43079 ce0bc496b725cca4a56e2d046d30f71b6c394608
child 43082 cf6e948513605fbbaa9432faf460dda6337f4677
push idunknown
push userunknown
push dateunknown
reviewersdougt
bugs565142
milestone1.9.3a5pre
Bug 565142 - Support startup on Android, patch by vlad, blassey, alexp, and me. r=dougt
toolkit/xre/Makefile.in
toolkit/xre/nsAndroidStartup.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsXREDirProvider.cpp
widget/src/android/AndroidBridge.h
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -42,20 +42,16 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = xulapp
 LIBRARY_NAME = xulapp_s
 LIBXUL_LIBRARY = 1
 
-
-
-
-
 FORCE_STATIC_LIB = 1
 
 XPIDLSRCS = \
 	nsINativeAppSupport.idl \
 	$(NULL)
 
 ifneq (,$(filter WINCE WINNT,$(OS_ARCH)))
 XPIDLSRCS += nsIWinAppHelper.idl
@@ -73,17 +69,17 @@ CPPSRCS = \
 ifdef MOZ_SPLASHSCREEN
 ifeq ($(OS_ARCH),WINCE)
 CPPSRCS += nsSplashScreenWin.cpp
 else
 CPPSRCS += nsSplashScreenDummy.cpp
 endif
 endif
 
-DEFINES += -DIMPL_XREAPI
+DEFINES += -DIMPL_XREAPI -DMOZ_APP_NAME='"$(MOZ_APP_NAME)"'
 
 ifndef BUILD_STATIC_LIBS
 CPPSRCS += nsEmbedFunctions.cpp
 endif
 
 ifdef MOZ_UPDATER
 CPPSRCS += nsUpdateDriver.cpp
 DEFINES += -DMOZ_UPDATER
@@ -128,16 +124,20 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 CMMSRCS += MacApplicationDelegate.mm
 CMMSRCS += MacAutoreleasePool.mm
 endif
 
 ifdef MOZ_X11
 CPPSRCS += nsX11ErrorHandler.cpp
 endif
 
+ifeq ($(OS_TARGET),Android)
+CPPSRCS += nsAndroidStartup.cpp
+endif
+
 SHARED_LIBRARY_LIBS += ../profile/src/$(LIB_PREFIX)profile_s.$(LIB_SUFFIX)
 
 ifdef MOZ_ENABLE_XREMOTE
 SHARED_LIBRARY_LIBS += $(DEPTH)/widget/src/xremoteclient/$(LIB_PREFIX)xremote_client_s.$(LIB_SUFFIX)
 LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/xremoteclient
 endif
 
 ifdef MOZ_CRASHREPORTER
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * 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. 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.
+ *
+ * The Original Code is Android port code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *   Michael Wu <mwu@mozilla.com>
+ *   Brad Lassey <blassey@mozilla.com>
+ *   Alex Pakhotin <alexp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <android/log.h>
+
+#include <jni.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "nsTArray.h"
+#include "nsString.h"
+#include "nsILocalFile.h"
+#include "nsAppRunner.h"
+#include "AndroidBridge.h"
+
+#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, MOZ_APP_NAME, args)
+
+static pthread_t gGeckoThread = 0;
+
+struct AutoAttachJavaThread {
+    AutoAttachJavaThread() {
+        attached = mozilla_AndroidBridge_SetMainThread((void*)pthread_self());
+    }
+    ~AutoAttachJavaThread() {
+        mozilla_AndroidBridge_SetMainThread(nsnull);
+        attached = PR_FALSE;
+    }
+
+    PRBool attached;
+};
+
+static void*
+GeckoStart(void *data)
+{
+    AutoAttachJavaThread attacher;
+    if (!attacher.attached)
+        return 0;
+
+    if (!data) {
+        LOG("Failed to get arguments for GeckoStart\n");
+        return 0;
+    }
+
+    nsresult rv;
+    nsCOMPtr<nsILocalFile> appini;
+    rv = NS_NewLocalFile(NS_LITERAL_STRING("/data/data/org.mozilla." MOZ_APP_NAME "/application.ini"),
+                         PR_FALSE,
+                         getter_AddRefs(appini));
+    if (NS_FAILED(rv)) {
+        LOG("Failed to create nsILocalFile for appdata\n");
+        return 0;
+    }
+
+    nsXREAppData *appData;
+    rv = XRE_CreateAppData(appini, &appData);
+    if (NS_FAILED(rv)) {
+        LOG("Failed to load application.ini from /data/data/org.mozilla." MOZ_APP_NAME "/application.ini\n");
+        return 0;
+    }
+
+    nsCOMPtr<nsILocalFile> xreDir;
+    rv = NS_NewLocalFile(NS_LITERAL_STRING("/data/data/org.mozilla." MOZ_APP_NAME),
+                         PR_FALSE,
+                         getter_AddRefs(xreDir));
+    if (NS_FAILED(rv)) {
+        LOG("Failed to create nsIFile for xreDirectory");
+        return 0;
+    }
+
+    appData->xreDirectory = xreDir.get();
+
+    // SpecialSystemDirectory.cpp sets its TMPDIR from this env var
+    setenv("TMPDIR", "/data/data/org.mozilla." MOZ_APP_NAME, 1);
+
+    nsTArray<char *> targs;
+    char *arg = strtok(static_cast<char *>(data), " ");
+    while (arg) {
+        targs.AppendElement(arg);
+        arg = strtok(NULL, " ");
+    }
+    targs.AppendElement(static_cast<char *>(nsnull));
+    
+    int result = XRE_main(targs.Length() - 1, targs.Elements(), appData);
+
+    if (result)
+        LOG("XRE_main returned %d", result);
+
+    XRE_FreeAppData(appData);
+
+    mozilla::AndroidBridge::Bridge()->NotifyXreExit();
+
+    free(targs[0]);
+    nsMemory::Free(data);
+    return 0;
+}
+
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs)
+{
+    // We need to put Gecko on a even more separate thread, because
+    // otherwise this JNI method never returns; this leads to problems
+    // with local references overrunning the local refs table, among
+    // other things, since GC can't ever run on them.
+
+    // Note that we don't have xpcom initialized yet, so we can't use the
+    // thread manager for this.  Instead, we use pthreads directly.
+
+    nsAutoString wargs;
+    int len = jenv->GetStringLength(jargs);
+    wargs.SetLength(jenv->GetStringLength(jargs));
+    jenv->GetStringRegion(jargs, 0, len, wargs.BeginWriting());
+    char *args = ToNewUTF8String(wargs);
+
+    if (pthread_create(&gGeckoThread, NULL, GeckoStart, args) != 0) {
+        LOG("pthread_create failed!");
+    }
+}
+
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -208,16 +208,20 @@
 #endif
 
 #ifdef MOZ_IPC
 #include "base/command_line.h"
 #endif
 
 #include "mozilla/FunctionTimer.h"
 
+#ifdef ANDROID
+#include "AndroidBridge.h"
+#endif
+
 #ifdef WINCE
 class WindowsMutex {
 public:
   WindowsMutex(const wchar_t *name) {
     mHandle = CreateMutexW(0, FALSE, name);
   }
 
   ~WindowsMutex() {
@@ -1744,16 +1748,19 @@ static nsresult LaunchChild(nsINativeApp
  
   if (aBlankCommandLine) {
     gRestartArgc = 1;
     gRestartArgv[gRestartArgc] = nsnull;
   }
 
   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
 
+#if defined(ANDROID)
+  mozilla::AndroidBridge::Bridge()->ScheduleRestart();
+#else
 #if defined(XP_MACOSX)
   SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
   LaunchChildMac(gRestartArgc, gRestartArgv);
 #else
   nsCOMPtr<nsILocalFile> lf;
   nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
   if (NS_FAILED(rv))
     return rv;
@@ -1796,16 +1803,17 @@ static nsresult LaunchChild(nsINativeApp
 
   PRInt32 exitCode;
   PRStatus failed = PR_WaitProcess(process, &exitCode);
   if (failed || exitCode)
     return NS_ERROR_FAILURE;
 #endif // XP_OS2 series
 #endif // WP_WIN
 #endif // WP_MACOSX
+#endif // ANDROID
 
   return NS_ERROR_LAUNCHED_CHILD_PROCESS;
 }
 
 static const char kProfileProperties[] =
   "chrome://mozapps/locale/profile/profileSelection.properties";
 
 static nsresult
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -1170,16 +1170,23 @@ nsXREDirProvider::GetUserDataDirectoryHo
     return NS_ERROR_FAILURE;
 
   int len = strlen(appDir);
   appDir[len]   = '/';
   appDir[len+1] = '\0';
 
   rv = NS_NewNativeLocalFile(nsDependentCString(appDir), PR_TRUE,
                              getter_AddRefs(localDir));
+#elif defined(ANDROID)
+  // used for setting the patch to our profile
+  // XXX: investigate putting the profile somewhere else
+  const char* homeDir = "/data/data/org.mozilla." MOZ_APP_NAME;
+
+  rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), PR_TRUE,
+                             getter_AddRefs(localDir));
 #elif defined(XP_UNIX)
   const char* homeDir = getenv("HOME");
   if (!homeDir || !*homeDir)
     return NS_ERROR_FAILURE;
 
   rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), PR_TRUE,
                              getter_AddRefs(localDir));
 #else
@@ -1408,16 +1415,22 @@ nsXREDirProvider::AppendProfilePath(nsIF
     if (gAppData->vendor) {
       rv = aFile->AppendNative(nsDependentCString(gAppData->vendor));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     rv = aFile->AppendNative(nsDependentCString(gAppData->name));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
+#elif defined(ANDROID)
+  // The directory used for storing profiles
+  // The parent of this directory is set in GetUserDataDirectoryHome
+  // XXX: handle gAppData->profile properly
+  rv = aFile->AppendNative(nsDependentCString("mozilla"));
+  NS_ENSURE_SUCCESS(rv, rv);
 #elif defined(XP_UNIX)
   // Make it hidden (i.e. using the ".")
   nsCAutoString folder(".");
 
   if (gAppData->profile) {
     // Skip any leading path characters
     const char* profileStart = gAppData->profile;
     while (*profileStart == '/' || *profileStart == '\\')
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -145,10 +145,11 @@ protected:
     jmethodID jNotifyXreExit;
     jmethodID jScheduleRestart;
     jmethodID jGetOutstandingDrawEvents;
 };
 
 }
 
 extern "C" JNIEnv * GetJNIForThread();
+extern PRBool mozilla_AndroidBridge_SetMainThread(void *);
 
 #endif /* AndroidBridge_h__ */