/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Set up values for System.getProperties().
*/
#include "Dalvik.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)
{
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);
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 "put" method for this class.
*
* Returns NULL and throws an exception if not found.
*/
static Method* getPut(ClassObject* clazz)
{
Method* put;
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, ALLOC_DEFAULT);
valueStr = dvmCreateStringFromCstr(value, ALLOC_DEFAULT);
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);
}
/*
* Create the VM-default system properties.
*
* We can do them here, or do them in interpreted code with lots of native
* methods to get bits and pieces. This is a bit smaller.
*/
void dvmCreateDefaultProperties(Object* propObj)
{
Method* put = getPut(propObj->clazz);
if (put == NULL)
return;
struct utsname info;
uname(&info);
/* constant strings that are used multiple times below */
const char *projectUrl = "http://www.android.com/";
const char *projectName = "The Android Project";
/*
* These are listed in the docs.
*/
setProperty(propObj, put, "java.boot.class.path", gDvm.bootClassPathStr);
setProperty(propObj, put, "java.class.path", gDvm.classPathStr);
setProperty(propObj, put, "java.class.version", "46.0");
setProperty(propObj, put, "java.compiler", "");
setProperty(propObj, put, "java.ext.dirs", "");
if (getenv("JAVA_HOME") != NULL) {
setProperty(propObj, put, "java.home", getenv("JAVA_HOME"));
} else {
setProperty(propObj, put, "java.home", "/system");
}
setProperty(propObj, put, "java.io.tmpdir", "/tmp");
setProperty(propObj, put, "java.library.path", getenv("LD_LIBRARY_PATH"));
setProperty(propObj, put, "java.net.preferIPv6Addresses", "true");
setProperty(propObj, put, "java.vendor", projectName);
setProperty(propObj, put, "java.vendor.url", projectUrl);
setProperty(propObj, put, "java.version", "0");
setProperty(propObj, put, "java.vm.name", "Dalvik");
setProperty(propObj, put, "java.vm.specification.name",
"Dalvik Virtual Machine Specification");
setProperty(propObj, put, "java.vm.specification.vendor", projectName);
setProperty(propObj, put, "java.vm.specification.version", "0.9");
setProperty(propObj, put, "java.vm.vendor", projectName);
char tmpBuf[64];
sprintf(tmpBuf, "%d.%d.%d",
DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
setProperty(propObj, put, "java.vm.version", tmpBuf);
setProperty(propObj, put, "java.specification.name",
"Dalvik Core Library");
setProperty(propObj, put, "java.specification.vendor", projectName);
setProperty(propObj, put, "java.specification.version", "0.9");
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.home", getenv("HOME"));
setProperty(propObj, put, "user.name", getenv("USER"));
char path[PATH_MAX];
setProperty(propObj, put, "user.dir", getcwd(path, sizeof(path)));
setProperty(propObj, put, "file.separator", "/");
setProperty(propObj, put, "line.separator", "\n");
setProperty(propObj, put, "path.separator", ":");
/*
* These show up elsewhere, so do them here too.
*/
setProperty(propObj, put, "java.runtime.name", "Android Runtime");
setProperty(propObj, put, "java.runtime.version", "0.9");
setProperty(propObj, put, "java.vm.vendor.url", projectUrl);
setProperty(propObj, put, "file.encoding", "UTF-8");
setProperty(propObj, put, "user.language", "en");
setProperty(propObj, put, "user.region", "US");
/*
* These are unique to Android/Dalvik.
*/
setProperty(propObj, put, "android.vm.dexfile", "true");
}
/*
* Add anything specified on the command line.
*/
void dvmSetCommandLineProperties(Object* propObj)
{
Method* put = getPut(propObj->clazz);
int i;
if (put == NULL)
return;
for (i = 0; i < gDvm.numProps; i++) {
const char* value;
/* 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);
}
}
/*
* Get a property by calling System.getProperty(key).
*
* Returns a newly-allocated string, or NULL on failure or key not found.
* (Unexpected failures will also raise an exception.)
*/
char* dvmGetProperty(const char* key)
{
ClassObject* system;
Method* getProp;
StringObject* keyObj = NULL;
StringObject* valueObj;
char* result = NULL;
assert(key != NULL);
system = dvmFindSystemClass("Ljava/lang/System;");
if (system == NULL)
goto bail;
getProp = dvmFindDirectMethodByDescriptor(system, "getProperty",
"(Ljava/lang/String;)Ljava/lang/String;");
if (getProp == NULL) {
LOGW("Could not find getProperty(String) in java.lang.System\n");
goto bail;
}
keyObj = dvmCreateStringFromCstr(key, ALLOC_DEFAULT);
if (keyObj == NULL)
goto bail;
JValue val;
dvmCallMethod(dvmThreadSelf(), getProp, NULL, &val, keyObj);
valueObj = (StringObject*) val.l;
if (valueObj == NULL)
goto bail;
result = dvmCreateCstrFromString(valueObj);
/* fall through with result */
bail:
dvmReleaseTrackedAlloc((Object*)keyObj, NULL);
return result;
}