Merge "Clean up argc / argv processing for runtime args."
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index bdbb08c..e0290c3 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -32,30 +32,20 @@
 public:
     AppRuntime(char* argBlockStart, const size_t argBlockLength)
         : AndroidRuntime(argBlockStart, argBlockLength)
-        , mParentDir(NULL)
-        , mClassName(NULL)
         , mClass(NULL)
-        , mArgC(0)
-        , mArgV(NULL)
     {
     }
 
-#if 0
-    // this appears to be unused
-    const char* getParentDir() const
-    {
-        return mParentDir;
-    }
-#endif
-
-    const char* getClassName() const
-    {
-        return mClassName;
+    void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {
+        mClassName = className;
+        for (int i = 0; i < argc; ++i) {
+             mArgs.add(String8(argv[i]));
+        }
     }
 
     virtual void onVmCreated(JNIEnv* env)
     {
-        if (mClassName == NULL) {
+        if (mClassName.isEmpty()) {
             return; // Zygote. Nothing to do here.
         }
 
@@ -72,10 +62,10 @@
          * executing boot class Java code and thereby deny ourselves access to
          * non-boot classes.
          */
-        char* slashClassName = toSlashClassName(mClassName);
+        char* slashClassName = toSlashClassName(mClassName.string());
         mClass = env->FindClass(slashClassName);
         if (mClass == NULL) {
-            ALOGE("ERROR: could not find class '%s'\n", mClassName);
+            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
         }
         free(slashClassName);
 
@@ -89,7 +79,7 @@
         proc->startThreadPool();
 
         AndroidRuntime* ar = AndroidRuntime::getRuntime();
-        ar->callMain(mClassName, mClass, mArgC, mArgV);
+        ar->callMain(mClassName, mClass, mArgs);
 
         IPCThreadState::self()->stopProcess();
     }
@@ -115,11 +105,9 @@
     }
 
 
-    const char* mParentDir;
-    const char* mClassName;
+    String8 mClassName;
+    Vector<String8> mArgs;
     jclass mClass;
-    int mArgC;
-    const char* const* mArgV;
 };
 
 }
@@ -155,7 +143,26 @@
     argc--;
     argv++;
 
-    // Everything up to '--' or first non '-' arg goes to the vm
+    // Everything up to '--' or first non '-' arg goes to the vm.
+    //
+    // The first argument after the VM args is the "parent dir", which
+    // is currently unused.
+    //
+    // After the parent dir, we expect one or more the following internal
+    // arguments :
+    //
+    // --zygote : Start in zygote mode
+    // --start-system-server : Start the system server.
+    // --application : Start in application (stand alone, non zygote) mode.
+    // --nice-name : The nice name for this process.
+    //
+    // For non zygote starts, these arguments will be followed by
+    // the main class name. All remaining arguments are passed to
+    // the main method of this class.
+    //
+    // For zygote starts, all remaining arguments are passed to the zygote.
+    // main function.
+
 
     int i = runtime.addVmArguments(argc, argv);
 
@@ -163,14 +170,13 @@
     bool zygote = false;
     bool startSystemServer = false;
     bool application = false;
-    const char* parentDir = NULL;
     const char* niceName = NULL;
-    const char* className = NULL;
+    String8 className;
+
+    ++i;  // Skip unused "parent dir" argument.
     while (i < argc) {
         const char* arg = argv[i++];
-        if (!parentDir) {
-            parentDir = arg;
-        } else if (strcmp(arg, "--zygote") == 0) {
+        if (strcmp(arg, "--zygote") == 0) {
             zygote = true;
             niceName = "zygote";
         } else if (strcmp(arg, "--start-system-server") == 0) {
@@ -180,28 +186,41 @@
         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
             niceName = arg + 12;
         } else {
-            className = arg;
+            className.setTo(arg);
             break;
         }
     }
 
+    Vector<String8> args;
+    if (!className.isEmpty()) {
+        // We're not in zygote mode, the only argument we need to pass
+        // to RuntimeInit is the application argument.
+        //
+        // The Remainder of args get passed to startup class main(). Make
+        // copies of them before we overwrite them with the process name.
+        args.add(application ? String8("application") : String8("tool"));
+        runtime.setClassNameAndArgs(className, argc - i, argv + i);
+    } else {
+        if (startSystemServer) {
+            args.add(String8("start-system-server"));
+        }
+
+        // In zygote mode, pass all remaining arguments to the zygote
+        // main() method.
+        for (; i < argc; ++i) {
+            args.add(String8(argv[i]));
+        }
+    }
+
     if (niceName && *niceName) {
         runtime.setArgv0(niceName);
         set_process_name(niceName);
     }
 
-    runtime.mParentDir = parentDir;
-
     if (zygote) {
-        runtime.start("com.android.internal.os.ZygoteInit",
-                startSystemServer ? "start-system-server" : "");
+        runtime.start("com.android.internal.os.ZygoteInit", args);
     } else if (className) {
-        // Remainder of args get passed to startup class main()
-        runtime.mClassName = className;
-        runtime.mArgC = argc - i;
-        runtime.mArgV = argv + i;
-        runtime.start("com.android.internal.os.RuntimeInit",
-                application ? "application" : "tool");
+        runtime.start("com.android.internal.os.RuntimeInit", args);
     } else {
         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
         app_usage();
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index cce4e0d..362a54e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -270,13 +270,13 @@
     strlcpy(mArgBlockStart, argv0, mArgBlockLength);
 }
 
-status_t AndroidRuntime::callMain(const char* className,
-    jclass clazz, int argc, const char* const argv[])
+status_t AndroidRuntime::callMain(const String8& className, jclass clazz,
+    const Vector<String8>& args)
 {
     JNIEnv* env;
     jmethodID methodId;
 
-    ALOGD("Calling main entry %s", className);
+    ALOGD("Calling main entry %s", className.string());
 
     env = getJNIEnv();
     if (clazz == NULL || env == NULL) {
@@ -285,7 +285,7 @@
 
     methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
     if (methodId == NULL) {
-        ALOGE("ERROR: could not find method %s.main(String[])\n", className);
+        ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());
         return UNKNOWN_ERROR;
     }
 
@@ -296,11 +296,12 @@
     jclass stringClass;
     jobjectArray strArray;
 
+    const size_t numArgs = args.size();
     stringClass = env->FindClass("java/lang/String");
-    strArray = env->NewObjectArray(argc, stringClass, NULL);
+    strArray = env->NewObjectArray(numArgs, stringClass, NULL);
 
-    for (int i = 0; i < argc; i++) {
-        jstring argStr = env->NewStringUTF(argv[i]);
+    for (size_t i = 0; i < numArgs; i++) {
+        jstring argStr = env->NewStringUTF(args[i].string());
         env->SetObjectArrayElement(strArray, i, argStr);
     }
 
@@ -872,20 +873,23 @@
  * Passes the main function two arguments, the class name and the specified
  * options string.
  */
-void AndroidRuntime::start(const char* className, const char* options)
+void AndroidRuntime::start(const char* className, const Vector<String8>& options)
 {
     ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
             className != NULL ? className : "(unknown)");
 
+    static const String8 startSystemServer("start-system-server");
+
     /*
      * 'startSystemServer == true' means runtime is obsolete and not run from
      * init.rc anymore, so we print out the boot start event here.
      */
-    if (strcmp(options, "start-system-server") == 0) {
-        /* track our progress through the boot sequence */
-        const int LOG_BOOT_PROGRESS_START = 3000;
-        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
-                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+    for (size_t i = 0; i < options.size(); ++i) {
+        if (options[i] == startSystemServer) {
+           /* track our progress through the boot sequence */
+           const int LOG_BOOT_PROGRESS_START = 3000;
+           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+        }
     }
 
     const char* rootDir = getenv("ANDROID_ROOT");
@@ -926,17 +930,20 @@
     jclass stringClass;
     jobjectArray strArray;
     jstring classNameStr;
-    jstring optionsStr;
 
     stringClass = env->FindClass("java/lang/String");
     assert(stringClass != NULL);
-    strArray = env->NewObjectArray(2, stringClass, NULL);
+    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
     assert(strArray != NULL);
     classNameStr = env->NewStringUTF(className);
     assert(classNameStr != NULL);
     env->SetObjectArrayElement(strArray, 0, classNameStr);
-    optionsStr = env->NewStringUTF(options);
-    env->SetObjectArrayElement(strArray, 1, optionsStr);
+
+    for (size_t i = 0; i < options.size(); ++i) {
+        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
+        assert(optionsStr != NULL);
+        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
+    }
 
     /*
      * Start VM.  This thread becomes the main thread of the VM, and will
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 6f2af90..3dfdb46 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -55,8 +55,7 @@
     /**
      * Call a class's static main method with the given arguments,
      */
-    status_t callMain(const char* className, jclass clazz, int argc,
-        const char* const argv[]);
+    status_t callMain(const String8& className, jclass clazz, const Vector<String8>& args);
 
     /**
      * Find a class, with the input either of the form
@@ -66,7 +65,7 @@
 
     int addVmArguments(int argc, const char* const argv[]);
 
-    void start(const char *classname, const char* options);
+    void start(const char *classname, const Vector<String8>& options);
 
     void exit(int code);