javaruntimes/installer/starterdll/src/main.cpp
branchRCL_3
changeset 14 04becd199f91
child 17 0fd27995241b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javaruntimes/installer/starterdll/src/main.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,397 @@
+/*
+* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Main program for the JavaInstaller process
+*
+*/
+
+
+#include <unistd.h>
+#include <string.h>
+// next three includes are for semaphores
+#include <sys/sem.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef __SYMBIAN32__
+#include "javauids.h"
+#endif
+#include "comms.h"
+#include "commsclientendpoint.h"
+#include "exceptionbase.h"
+#include "javacommonutils.h"
+#include "javaoslayer.h"
+#include "jvmstarter.h"
+#include "logger.h"
+#include "runtimeexception.h"
+#include "runtimestarterutils.h"
+
+using namespace java::comms;
+using namespace java::runtime;
+using namespace java::util;
+
+const wchar_t* const INSTALLER_MAIN_CLASS =
+    L"com.nokia.mj.impl.installer.Installer";
+
+int startJvm(int argc, char *argv[]);
+
+#ifdef __WINS__
+#include <e32ldr.h>
+#endif //__WINS__
+
+// random small int value
+#define SEM_KEY 1823 // codescanner::magicnumbers
+// same as Symbian KErrAlreadyExists
+#define INSTALLER_ALREADY_RUNNING -11 // codescanner::magicnumbers
+// semaphore operation error, same as Symbian KErrLocked
+#define SEMAPHORE_ERROR -22 // codescanner::magicnumbers
+// Ubuntu semaphore headers do not define these contants
+#ifndef SEM_R
+#define SEM_R S_IRUSR
+#endif
+#ifndef SEM_A
+#define SEM_A S_IWUSR
+#endif
+
+#ifndef __SYMBIAN32__
+extern "C"
+#endif //__SYMBIAN32__
+
+int dllMain(int argc, char *argv[])
+{
+    JELOG(EJavaRuntime, "INSTALLER main()");
+    JavaOsLayer::startUpTrace("INSTALLER main() start", -1, -1);
+
+#ifdef __SYMBIAN32__
+
+    // Only processes with TrustedUI capability are allowed to start
+    // Java Installer in S60 device (e.g. TCK runner, preinstaller,
+    // appconverter, javacleaner, AppInstUI,javainstaller,
+    // javapostupdater and SDK Debug Agent)
+
+    TSecureId creatorSecId(User::CreatorSecureId());
+    if (!User::CreatorHasCapability(ECapabilityTrustedUI))
+    {
+        ELOG1(EJavaRuntime,
+              "INSTALLER main: Process %x is not allowed to launch Java Installer, since it is missing TrustedUI capability.",
+              creatorSecId.iId);
+        return KErrPermissionDenied;
+    }
+
+#endif
+
+#ifdef __SYMBIAN32__
+    _LIT(KJavaInstallerProcessName, "JavaInstaller");
+    _LIT(KJavaInstallerThreadName, "JavaInstallerMainThread");
+    // Rename installer process and main thread.
+    TInt err = User::RenameProcess(KJavaInstallerProcessName);
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaRuntime,
+              "INSTALLER main: cannot change process name to JavaInstaller, err %d", err);
+    }
+    err = User::RenameThread(KJavaInstallerThreadName);
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaRuntime,
+              "INSTALLER main: cannot change main thread name to "
+              "JavaInstallerMainThread, err %d", err);
+    }
+#endif //__SYMBIAN32__
+
+    // Allow running only one instance of this process at same time.
+
+    // Because of S60 semop implementation (semop waits even if
+    // IPC_NOWAIT has been specified) -> use semaphore access control
+    // to limit number of instances to one.
+
+#ifdef __SYMBIAN32__
+    int perm = 0x1FF; // all permissions to every process
+#else
+    // Create one System V / XSI semaphore accessible only by this process
+    int perm = (SEM_R | SEM_A);
+#endif //__SYMBIAN32__
+    int semid = semget(SEM_KEY, 1, IPC_CREAT | perm);
+
+    // Increase process instance count by one.
+    // This increase is automatically undone when this process exits.
+    sembuf st = {0, 1, SEM_UNDO | IPC_NOWAIT};
+    int ret = semop(semid, &st, 1);
+    if (-1 == ret)
+    {
+        ELOG(EJavaRuntime, "INSTALLER main: semop failed");
+        JavaOsLayer::startUpTrace("INSTALLER main() end", -1, -1);
+        return SEMAPHORE_ERROR;
+    }
+
+    // Get the current instance count
+    ret = semctl(semid, 0, GETVAL);
+    if (-1 == ret)
+    {
+        ELOG(EJavaRuntime, "INSTALLER main: semctl failed");
+        JavaOsLayer::startUpTrace("INSTALLER main() end", -1, -1);
+        return SEMAPHORE_ERROR;
+    }
+    else if (ret > 1)
+    {
+        WLOG(EJavaRuntime, "Installer already running. Exiting.");
+        JavaOsLayer::startUpTrace("INSTALLER main() end", -1, -1);
+        return INSTALLER_ALREADY_RUNNING;
+    }
+
+    int result = -1;
+    try
+    {
+        // Start the VM.
+        result = startJvm(argc, argv);
+    }
+    catch (RuntimeException& e)
+    {
+        ELOG1(EJavaRuntime, "INSTALLER main() RuntimeException caught: %s ",
+              e.toString().c_str());
+    }
+    catch (ExceptionBase& e)
+    {
+        ELOG1(EJavaRuntime, "INSTALLER main() ExceptionBase caught: %s ",
+              e.toString().c_str());
+    }
+    catch (std::exception& e)
+    {
+        ELOG1(EJavaRuntime, "INSTALLER main() Exception %s caught", e.what());
+    }
+
+    // Try to remove the semaphore, ignore possible error
+    ret = semctl(semid, 0, IPC_RMID);
+    if (-1 == ret)
+    {
+        ELOG1(EJavaRuntime, "INSTALLER main() Remove semaphore failed, err %d",
+              errno);
+    }
+
+    LOG1(EJavaRuntime, EInfo, "INSTALLER main() exit = %d", result);
+    JavaOsLayer::startUpTrace("INSTALLER main() end", -1, -1);
+    return result;
+}
+
+#ifdef __SYMBIAN32__
+/**
+ *  Start Java Captain process
+ */
+TInt startJavaCaptain()
+{
+    // Start 'systemams.exe' in S60 5.0 (it will start javacaptain) and
+    // 'javacaptain.exe' in 9.2 and later
+
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+    _LIT(KJavaCaptainExe, "systemams.exe");
+#else
+    _LIT(KJavaCaptainExe, "javacaptain.exe");
+#endif
+    _LIT(KJavaCaptainArg, "");
+    RProcess proc;
+    int err = proc.Create(KJavaCaptainExe, KJavaCaptainArg);
+    if (err == KErrNone)
+    {
+        proc.Resume();
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+        LOG(EJavaRuntime, EInfo,
+            "InstallerStarter: startJavaCaptain systemams.exe was started ok");
+#else
+        LOG(EJavaRuntime, EInfo,
+            "InstallerStarter: startJavaCaptain javacaptain.exe was started ok");
+#endif
+
+        // Wait 3 seconds so that Java Captain has time to start
+        User::After(3000000);
+    }
+    else
+    {
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+        ELOG1(EJavaRuntime,
+              "InstallerStarter: startJavaCaptain start systemams.exe failed: %d", err);
+#else
+        ELOG1(EJavaRuntime,
+              "InstallerStarter: startJavaCaptain start javacaptain.exe failed: %d", err);
+#endif
+    }
+
+    proc.Close();
+    return err;
+}
+#endif
+
+int startJvm(int argc, char *argv[])
+{
+    // Create instance of RuntimeStarterUtils for thread supervisioning.
+    std::auto_ptr<RuntimeStarterUtils> starterUtils(new RuntimeStarterUtils()); // codescanner::nonleavenew
+    starterUtils->startThreadSupervisor();
+
+    // Create Comms endpoint for JavaCaptain.
+    std::auto_ptr<CommsClientEndpoint> comms(
+        new CommsClientEndpoint(L"InstallerJavaCaptain"));
+    int result = comms->connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
+
+#ifdef __SYMBIAN32__
+    if (KErrNotFound == result)
+    {
+        ELOG(EJavaRuntime,
+             "InstallerStarter: Java Captain was not running. Trying to restart it.");
+
+        // Java Captain is not running, try to start it
+        result = startJavaCaptain();
+        if (KErrNone == result)
+        {
+            result = comms->connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
+        }
+    }
+#endif
+
+    if (result != 0)
+    {
+        ELOG1(EJavaRuntime,
+              "InstallerStarter: Connection to JavaCaptain failed: Reason = %d",
+              result);
+    }
+
+    // Another Comms Endpoint for TCK Runner or preinstaller
+    std::auto_ptr<CommsClientEndpoint> commsPoll;
+
+    // If installer is started in 'poll' mode, connect also to TCK Runner,
+    // preinstaller or javaappconverter. Command line is
+    // 'javainstaller poll -address=(tck|preinstall|convert) [options]'
+    const int minArgCount = 3;
+    if (argc >= minArgCount)
+    {
+        if (!strcmp(argv[1], "poll")) // codescanner::accessArrayElementWithoutCheck2
+        {
+            int connected = 0;
+            // next argument must be -address=(tck|preinstaller|convert)
+            char* val = strpbrk(argv[2], "="); // codescanner::accessArrayElementWithoutCheck2
+            if (val != 0)
+            {
+                val++;
+                int commsAddress = 0;
+                if (!strcmp(val, "tck"))
+                {
+                    commsAddress = IPC_ADDRESS_JAVA_TCK_RUNNER_C;
+                }
+                else if (!strcmp(val, "preinstall"))
+                {
+                    commsAddress = IPC_ADDRESS_JAVA_PREINSTALLER_C;
+                }
+                else if (!strcmp(val, "convert"))
+                {
+                    commsAddress = IPC_ADDRESS_JAVA_APPCONVERTER_C;
+                }
+                else if (!strcmp(val, "debugapi"))
+                {
+                    commsAddress = IPC_ADDRESS_JAVA_DEBUGAPI_C;
+                }
+                else
+                {
+                    ELOG1(EJavaRuntime, "InstallerStarter: unknown comms "
+                          "poll address %s", val);
+                }
+
+                if (0 != commsAddress)
+                {
+                    commsPoll.reset(new CommsClientEndpoint(L"InstallerCommsPoll")); // codescanner::nonleavenew
+                    result = commsPoll->connect(commsAddress);
+                    if (0 != result)
+                    {
+                        ELOG3(EJavaRuntime,
+                              "InstallerStarter: Connection to %s (address %d) failed: Reason = %d",
+                              val, commsAddress, result);
+                    }
+                    else
+                    {
+                        connected = 1;
+                    }
+                }
+            }
+            else
+            {
+                ELOG1(EJavaRuntime, "InstallerStarter: No valid -address argument. Arg is %s",
+                      argv[2]); // codescanner::accessArrayElementWithoutCheck2
+            }
+
+            // Installer cannot be started in 'poll' mode unless connection is ok
+            if (!connected)
+            {
+                ELOG(EJavaRuntime,
+                     "InstallerStarter: Installer cannot be started in poll mode because connection to initiator fails.");
+                std::string errorStr("Installer cannot start in poll mode");
+                throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
+            }
+        }
+    }
+
+    // Create starter for starting the JVM
+    std::auto_ptr<JvmStarter>
+    jvm(JvmStarter::getJvmStarterInstance(JvmStarter::CDC,
+                                          L"Installer"));
+
+    // Set the debugging features available provided by the captain.
+    starterUtils->enableDevelopmentFeatures(*jvm.get());
+
+    // Set the old heap size to 512K
+    const int oldHeapSize = 512;
+    jvm->overrideOldHeapSize(oldHeapSize);
+
+    jvm->enableThreadDumping();
+
+    jvm->setMainClass(INSTALLER_MAIN_CLASS);
+
+    jvm->appendSystemProperty(L"-Dcom.nokia.rt.port=installer");
+
+    for (int i = 1; i < argc; ++i)
+    {
+        jvm->appendApplicationArgument(
+            JavaCommonUtils::utf8ToWstring(argv[i])); // codescanner::accessArrayElementWithoutCheck2
+    }
+
+#ifdef RD_JAVA_INSTALLERUI_ENABLED
+    jvm->appendSystemProperty(
+        L"-Dcom.nokia.mj.impl.installer.ui="
+        L"com.nokia.mj.impl.installer.ui.eswt.InstallerUiEswt");
+#endif
+
+    std::wstring extendedBootClassPath;
+    // This call is platform dependent.
+    starterUtils->getExtBootClassPath(extendedBootClassPath);
+    if (extendedBootClassPath.length() > 0)
+    {
+        // Provide the bootclasspath also as a system propery
+        // to be used for security extensions.
+        std::wstring addOnList(L"-Dcom.nokia.mj.addon.list=");
+        addOnList += extendedBootClassPath;
+        jvm->appendSystemProperty(addOnList);
+    }
+
+    // Start the JVM.
+    return jvm->startJvm();
+}
+
+#ifdef __SYMBIAN32__
+#include "javasymbianoslayer.h"
+
+EXPORT_C FuncPtr findDllMethod(const char* funcName)
+{
+    FuncPtr ptr = 0;
+    if (strcmp(funcName, "dllMain") == 0)
+    {
+        ptr = (FuncPtr)dllMain;
+    }
+    return ptr;
+}
+#endif //__SYMBIAN32__