Move more system propery handling into managed code.

Bug: 3413364
Change-Id: I044ed1b11e919bb1c589c626b613faf85157fb64
diff --git a/vm/Globals.h b/vm/Globals.h
index f96cbf2..55c4347 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -29,6 +29,7 @@
 #ifndef _DALVIK_GLOBALS
 #define _DALVIK_GLOBALS
 
+#include <cutils/array.h>
 #include <stdarg.h>
 #include <pthread.h>
 
@@ -181,11 +182,11 @@
     bool        optimizing;
 
     /*
-     * java.lang.System properties set from the command line.
+     * java.lang.System properties set from the command line with -D.
+     * This is effectively a set, where later entries override earlier
+     * ones.
      */
-    int         numProps;
-    int         maxProps;
-    char**      propList;
+    Array*      properties;
 
     /*
      * Where the VM goes to find system classes.
diff --git a/vm/Init.c b/vm/Init.c
index 2b590bc..4c731c9 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -746,8 +746,17 @@
             gDvm.bootClassPathStr = allPath;
 
         } else if (strncmp(argv[i], "-D", 2) == 0) {
-            /* set property */
-            dvmAddCommandLineProperty(argv[i] + 2);
+            /* Properties are handled in managed code. We just check syntax. */
+            if (strchr(argv[i], '=') == NULL) {
+                dvmFprintf(stderr, "Bad system property setting: \"%s\"\n",
+                    argv[i]);
+                return -1;
+            }
+            if (arrayAdd(gDvm.properties, strdup(argv[i] + 2)) == -1) {
+                dvmFprintf(stderr, "Can't set system property: \"%s\"\n",
+                    argv[i]);
+                return -1;
+            }
 
         } else if (strcmp(argv[i], "-jar") == 0) {
             // TODO: handle this; name of jar should be in argv[i+1]
@@ -1147,12 +1156,12 @@
     for (i = 0; i < argc; i++)
         LOGV("  %d: '%s'\n", i, argv[i]);
 
-    setCommandLineDefaults();
-
     /* prep properties storage */
-    if (!dvmPropertiesStartup(argc))
+    if (!dvmPropertiesStartup())
         goto fail;
 
+    setCommandLineDefaults();
+
     /*
      * Process the option flags (if any).
      */
diff --git a/vm/Properties.c b/vm/Properties.c
index 312691a..493ce23 100644
--- a/vm/Properties.c
+++ b/vm/Properties.c
@@ -18,154 +18,44 @@
  */
 #include "Dalvik.h"
 
+#include <cutils/array.h>
 #include <stdlib.h>
 #include <sys/utsname.h>
 #include <limits.h>
 #include <unistd.h>
 
-/*
- * Create some storage for properties read from the command line.
- */
-bool dvmPropertiesStartup(int maxProps)
+bool dvmPropertiesStartup(void)
 {
-    gDvm.maxProps = maxProps;
-    if (maxProps > 0) {
-        gDvm.propList = (char**) malloc(maxProps * sizeof(char*));
-        if (gDvm.propList == NULL)
-            return false;
-    }
-    gDvm.numProps = 0;
-
-    return true;
-}
-
-/*
- * Clean up.
- */
-void dvmPropertiesShutdown(void)
-{
-    int i;
-
-    for (i = 0; i < gDvm.numProps; i++)
-        free(gDvm.propList[i]);
-    free(gDvm.propList);
-    gDvm.propList = NULL;
-}
-
-/*
- * Add a property specified on the command line.  "argStr" has the form
- * "name=value".  "name" must have nonzero length.
- *
- * Returns "true" if argStr appears valid.
- */
-bool dvmAddCommandLineProperty(const char* argStr)
-{
-    char* mangle;
-    char* equals;
-
-    mangle = strdup(argStr);
-    if (mangle == NULL) {
+    gDvm.properties = arrayCreate();
+    if (gDvm.properties == NULL) {
         return false;
     }
-    equals = strchr(mangle, '=');
-    if (equals == NULL || equals == mangle) {
-        free(mangle);
-        return false;
-    }
-    *equals = '\0';
-
-    assert(gDvm.numProps < gDvm.maxProps);
-    gDvm.propList[gDvm.numProps++] = mangle;
-
-    return true;
-}
-
-
-/*
- * Find the "System.setProperty" method.
- *
- * Returns NULL and throws an exception if not found.
- */
-static Method* findSetProperty(ClassObject* clazz)
-{
-    Method* put = dvmFindVirtualMethodHierByDescriptor(clazz, "setProperty",
-            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
-    if (put == NULL) {
-        dvmThrowException("Ljava/lang/RuntimeException;",
-            "could not find setProperty(String,String) in Properties");
-        /* fall through to return */
-    }
-    return put;
-}
-
-/*
- * Set the value of the property.
- */
-static void setProperty(Object* propObj, Method* put, const char* key,
-    const char* value)
-{
-    StringObject* keyStr;
-    StringObject* valueStr;
-
-    if (value == NULL) {
-        /* unclear what to do; probably want to create prop w/ empty string */
-        value = "";
-    }
-
-    keyStr = dvmCreateStringFromCstr(key);
-    valueStr = dvmCreateStringFromCstr(value);
-    if (keyStr == NULL || valueStr == NULL) {
-        LOGW("setProperty string creation failed\n");
-        goto bail;
-    }
-
-    JValue unused;
-    dvmCallMethod(dvmThreadSelf(), put, propObj, &unused, keyStr, valueStr);
-
-bail:
-    dvmReleaseTrackedAlloc((Object*) keyStr, NULL);
-    dvmReleaseTrackedAlloc((Object*) valueStr, NULL);
-}
-
-/*
- * Fills the passed-in java.util.Properties with stuff only the VM knows, such
- * as the VM's exact version and properties set on the command-line with -D.
- */
-void dvmInitVmSystemProperties(Object* propObj)
-{
-    Method* put = findSetProperty(propObj->clazz);
-    int i;
-    struct utsname info;
-    char tmpBuf[64];
-    char path[PATH_MAX];
-
-    if (put == NULL)
-        return;
 
     /*
      * TODO: these are currently awkward to do in Java so we sneak them in
      * here. Only java.vm.version really needs to be in Dalvik.
      */
-    setProperty(propObj, put, "java.boot.class.path", gDvm.bootClassPathStr);
-    setProperty(propObj, put, "java.class.path", gDvm.classPathStr);
-    sprintf(tmpBuf, "%d.%d.%d",
-            DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
-    setProperty(propObj, put, "java.vm.version", tmpBuf);
+    struct utsname info;
     uname(&info);
-    setProperty(propObj, put, "os.arch", info.machine);
-    setProperty(propObj, put, "os.name", info.sysname);
-    setProperty(propObj, put, "os.version", info.release);
-    setProperty(propObj, put, "user.dir", getcwd(path, sizeof(path)));
+    char* s;
+    asprintf(&s, "os.arch=%s", info.machine);
+    arrayAdd(gDvm.properties, s);
+    asprintf(&s, "os.name=%s", info.sysname);
+    arrayAdd(gDvm.properties, s);
+    asprintf(&s, "os.version=%s", info.release);
+    arrayAdd(gDvm.properties, s);
 
-    /*
-     * Properties set on the command-line with -D.
-     */
-    for (i = 0; i < gDvm.numProps; i++) {
-        const char* value;
+    char path[PATH_MAX];
+    asprintf(&s, "user.dir=%s", getcwd(path, sizeof(path)));
+    arrayAdd(gDvm.properties, s);
 
-        /* value starts after the end of the key string */
-        for (value = gDvm.propList[i]; *value != '\0'; value++)
-            ;
-        setProperty(propObj, put, gDvm.propList[i], value+1);
+    return true;
+}
+
+void dvmPropertiesShutdown(void) {
+    int i = arraySize(gDvm.properties);
+    for (; i >= 0; --i) {
+        free(arrayGet(gDvm.properties, i));
     }
+    arrayFree(gDvm.properties);
 }
diff --git a/vm/Properties.h b/vm/Properties.h
index 7e53db4..138be41 100644
--- a/vm/Properties.h
+++ b/vm/Properties.h
@@ -22,13 +22,7 @@
 /*
  * Initialization.
  */
-bool dvmPropertiesStartup(int maxProps);
+bool dvmPropertiesStartup(void);
 void dvmPropertiesShutdown(void);
 
-/* add "-D" option to list */
-bool dvmAddCommandLineProperty(const char* argStr);
-
-/* called during property initialization */
-void dvmInitVmSystemProperties(Object* propObj);
-
 #endif /*_DALVIK_PROPERTIES*/
diff --git a/vm/UtfString.c b/vm/UtfString.c
index f560dac..d3acf0e 100644
--- a/vm/UtfString.c
+++ b/vm/UtfString.c
@@ -521,3 +521,40 @@
                   (const u2*) chars2->contents + offset2,
                   len1 * sizeof(u2));
 }
+
+ArrayObject* dvmCreateStringArray(char** strings, size_t count)
+{
+    Thread* self = dvmThreadSelf();
+
+    /*
+     * Allocate an array to hold the String objects.
+     */
+    ArrayObject* stringArray =
+        dvmAllocObjectArray(gDvm.classJavaLangString, count, ALLOC_DEFAULT);
+    if (stringArray == NULL) {
+        /* probably OOM */
+        LOGD("Failed allocating array of %d strings\n", count);
+        assert(dvmCheckException(self));
+        return NULL;
+    }
+
+    /*
+     * Create the individual String objects and add them to the array.
+     */
+    size_t i;
+    for (i = 0; i < count; i++) {
+        Object* str =
+            (Object*) dvmCreateStringFromCstr(strings[i]);
+        if (str == NULL) {
+            /* probably OOM; drop out now */
+            assert(dvmCheckException(self));
+            dvmReleaseTrackedAlloc((Object*) stringArray, self);
+            return NULL;
+        }
+        dvmSetObjectArrayElement(stringArray, i, str);
+        /* stored in tracked array, okay to release */
+        dvmReleaseTrackedAlloc(str, self);
+    }
+
+    return stringArray;
+}
diff --git a/vm/UtfString.h b/vm/UtfString.h
index b291f5a..793d8bc 100644
--- a/vm/UtfString.h
+++ b/vm/UtfString.h
@@ -56,6 +56,16 @@
 u4 dvmComputeStringHash(const StringObject* strObj);
 
 /*
+ * Create a java.lang.String[] from an array of C strings.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the returned array,
+ * but not on the individual elements.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+ArrayObject* dvmCreateStringArray(char** strings, size_t count);
+
+/*
  * Create a java/lang/String from a C string.
  *
  * The caller must call dvmReleaseTrackedAlloc() on the return value.
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index 55fb684..59fcb4c 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -21,6 +21,7 @@
 #include "native/InternalNativePriv.h"
 #include "hprof/Hprof.h"
 
+#include <cutils/array.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
@@ -55,57 +56,6 @@
 }
 
 /*
- * Convert an array of char* into a String[].
- *
- * Returns NULL on failure, with an exception raised.
- */
-static ArrayObject* convertStringArray(char** strings, size_t count)
-{
-    Thread* self = dvmThreadSelf();
-
-    /*
-     * Allocate an array to hold the String objects.
-     */
-    ClassObject* stringArrayClass =
-        dvmFindArrayClass("[Ljava/lang/String;", NULL);
-    if (stringArrayClass == NULL) {
-        /* shouldn't happen */
-        LOGE("Unable to find [Ljava/lang/String;\n");
-        dvmAbort();
-    }
-
-    ArrayObject* stringArray =
-        dvmAllocArrayByClass(stringArrayClass, count, ALLOC_DEFAULT);
-    if (stringArray == NULL) {
-        /* probably OOM */
-        LOGD("Failed allocating array of %d strings\n", count);
-        assert(dvmCheckException(self));
-        return NULL;
-    }
-
-    /*
-     * Create the individual String objects and add them to the array.
-     */
-    size_t i;
-    for (i = 0; i < count; i++) {
-        Object *str =
-            (Object *)dvmCreateStringFromCstr(strings[i]);
-        if (str == NULL) {
-            /* probably OOM; drop out now */
-            assert(dvmCheckException(self));
-            dvmReleaseTrackedAlloc((Object*)stringArray, self);
-            return NULL;
-        }
-        dvmSetObjectArrayElement(stringArray, i, str);
-        /* stored in tracked array, okay to release */
-        dvmReleaseTrackedAlloc(str, self);
-    }
-
-    dvmReleaseTrackedAlloc((Object*)stringArray, self);
-    return stringArray;
-}
-
-/*
  * static String[] getVmFeatureList()
  *
  * Return a set of strings describing available VM features (this is chiefly
@@ -115,22 +65,21 @@
 static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args,
     JValue* pResult)
 {
-    static const int MAX_FEATURE_COUNT = 10;
-    char* features[MAX_FEATURE_COUNT];
-    int idx = 0;
+    Array* features = arrayCreate();
 
     /* VM responds to DDMS method profiling requests */
-    features[idx++] = "method-trace-profiling";
-    features[idx++] = "method-trace-profiling-streaming";
+    arrayAdd(features, "method-trace-profiling");
+    arrayAdd(features, "method-trace-profiling-streaming");
     /* VM responds to DDMS heap dump requests */
-    features[idx++] = "hprof-heap-dump";
-    features[idx++] = "hprof-heap-dump-streaming";
+    arrayAdd(features, "hprof-heap-dump");
+    arrayAdd(features, "hprof-heap-dump-streaming");
 
-    assert(idx <= MAX_FEATURE_COUNT);
-
-    LOGV("+++ sending up %d features\n", idx);
-    ArrayObject* arrayObj = convertStringArray(features, idx);
-    RETURN_PTR(arrayObj);       /* will be null on OOM */
+    char** strings = (char**) arrayUnwrap(features);
+    int count = arraySize(features);
+    ArrayObject* result = dvmCreateStringArray(strings, count);
+    dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
+    arrayFree(features);
+    RETURN_PTR(result);
 }
 
 
diff --git a/vm/native/dalvik_system_VMRuntime.c b/vm/native/dalvik_system_VMRuntime.c
index 298db24..da529e4 100644
--- a/vm/native/dalvik_system_VMRuntime.c
+++ b/vm/native/dalvik_system_VMRuntime.c
@@ -20,6 +20,7 @@
 #include "Dalvik.h"
 #include "native/InternalNativePriv.h"
 
+#include <cutils/array.h>
 #include <limits.h>
 
 
@@ -158,22 +159,68 @@
     RETURN_VOID();
 }
 
+static void Dalvik_dalvik_system_VMRuntime_properties(const u4* args,
+    JValue* pResult)
+{
+    char** strings = (char**) arrayUnwrap(gDvm.properties);
+    int count = arraySize(gDvm.properties);
+    ArrayObject* result = dvmCreateStringArray(strings, count);
+    dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
+    RETURN_PTR(result);
+}
+
+static void returnCString(JValue* pResult, const char* s)
+{
+    Object* result = (Object*) dvmCreateStringFromCstr(s);
+    dvmReleaseTrackedAlloc(result, dvmThreadSelf());
+    RETURN_PTR(result);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4* args,
+    JValue* pResult)
+{
+    returnCString(pResult, gDvm.bootClassPathStr);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_classPath(const u4* args,
+    JValue* pResult)
+{
+    returnCString(pResult, gDvm.classPathStr);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_vmVersion(const u4* args,
+    JValue* pResult)
+{
+    char buf[64];
+    sprintf(buf, "%d.%d.%d",
+            DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
+    returnCString(pResult, buf);
+}
+
 const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
+    { "addressOf", "(Ljava/lang/Object;)J",
+        Dalvik_dalvik_system_VMRuntime_addressOf },
+    { "bootClassPath", "()Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_bootClassPath },
+    { "classPath", "()Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_classPath },
+    { "clearGrowthLimit", "()V",
+        Dalvik_dalvik_system_VMRuntime_clearGrowthLimit },
+    { "disableJitCompilation", "()V",
+        Dalvik_dalvik_system_VMRuntime_disableJitCompilation },
     { "getTargetHeapUtilization", "()F",
         Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization },
     { "nativeSetTargetHeapUtilization", "(F)V",
         Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization },
-     { "runFinalizationSync", "()V",
+    { "newNonMovableArray", "(Ljava/lang/Class;I)Ljava/lang/Object;",
+        Dalvik_dalvik_system_VMRuntime_newNonMovableArray },
+    { "properties", "()[Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_properties },
+    { "runFinalizationSync", "()V",
         Dalvik_dalvik_system_VMRuntime_runFinalizationSync },
     { "startJitCompilation", "()V",
         Dalvik_dalvik_system_VMRuntime_startJitCompilation },
-    { "disableJitCompilation", "()V",
-        Dalvik_dalvik_system_VMRuntime_disableJitCompilation },
-    { "newNonMovableArray", "(Ljava/lang/Class;I)Ljava/lang/Object;",
-        Dalvik_dalvik_system_VMRuntime_newNonMovableArray },
-    { "addressOf", "(Ljava/lang/Object;)J",
-        Dalvik_dalvik_system_VMRuntime_addressOf },
-    { "clearGrowthLimit", "()V",
-        Dalvik_dalvik_system_VMRuntime_clearGrowthLimit },
+    { "vmVersion", "()Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_vmVersion },
     { NULL, NULL, NULL },
 };
diff --git a/vm/native/java_lang_System.c b/vm/native/java_lang_System.c
index a4c4bc1..e9d8a48 100644
--- a/vm/native/java_lang_System.c
+++ b/vm/native/java_lang_System.c
@@ -343,14 +343,6 @@
     RETURN_INT(dvmIdentityHashCode(thisPtr));
 }
 
-static void Dalvik_java_lang_System_initVmSystemProperties(const u4* args,
-    JValue* pResult)
-{
-    Object* propObj = (Object*) args[0];
-    dvmInitVmSystemProperties(propObj);
-    RETURN_VOID();
-}
-
 /*
  * public static String mapLibraryName(String libname)
  */
@@ -386,8 +378,6 @@
         Dalvik_java_lang_System_currentTimeMillis },
     { "identityHashCode",  "(Ljava/lang/Object;)I",
         Dalvik_java_lang_System_identityHashCode },
-    { "initVmSystemProperties",  "(Ljava/util/Properties;)V",
-        Dalvik_java_lang_System_initVmSystemProperties },
     { "mapLibraryName",     "(Ljava/lang/String;)Ljava/lang/String;",
         Dalvik_java_lang_System_mapLibraryName },
     { "nanoTime",  "()J",