diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:09 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:09 -0800 |
| commit | 52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98 (patch) | |
| tree | 2eb01432fa3da41550dd622d29fb672509122b51 /simulator/app/PropertyServer.cpp | |
| parent | d4aee0c0caa00aa02d4c50ed28151591ac0456b5 (diff) | |
| download | android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.tar.gz android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.tar.bz2 android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.zip | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'simulator/app/PropertyServer.cpp')
| -rw-r--r-- | simulator/app/PropertyServer.cpp | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/simulator/app/PropertyServer.cpp b/simulator/app/PropertyServer.cpp new file mode 100644 index 000000000..0d6054fdd --- /dev/null +++ b/simulator/app/PropertyServer.cpp @@ -0,0 +1,467 @@ +// +// Copyright 2007 The Android Open Source Project +// +// Property sever. Mimics behavior provided on the device by init(8) and +// some code built into libc. +// + +// For compilers that support precompilation, include "wx/wx.h". +#include "wx/wxprec.h" + +// Otherwise, include all standard headers +#ifndef WX_PRECOMP +# include "wx/wx.h" +#endif +#include "wx/image.h" + +#include "PropertyServer.h" +#include "MyApp.h" +#include "Preferences.h" +#include "MainFrame.h" +#include "utils.h" + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> + + +using namespace android; + +const char* PropertyServer::kPropCheckJni = "ro.kernel.android.checkjni"; + +/* + * Destructor. + */ +PropertyServer::~PropertyServer(void) +{ + if (IsRunning()) { + // TODO: cause thread to stop, then Wait for it + } + printf("Sim: in ~PropertyServer()\n"); +} + +/* + * Create and run the thread. + */ +bool PropertyServer::StartThread(void) +{ + if (Create() != wxTHREAD_NO_ERROR) { + fprintf(stderr, "Sim: ERROR: can't create PropertyServer thread\n"); + return false; + } + + Run(); + return true; +} + + +/* + * Clear out the list. + */ +void PropertyServer::ClearProperties(void) +{ + typedef List<Property>::iterator PropIter; + + for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) { + pi = mPropList.erase(pi); + } +} + +/* + * Set default values for several properties. + */ +void PropertyServer::SetDefaultProperties(void) +{ + static const struct { + const char* key; + const char* value; + } propList[] = { + { "net.bt.name", "Android" }, + { "ro.kernel.mem", "60M" }, + { "ro.kernel.board_sardine.version", "4" }, + { "ro.kernel.console", "null" }, + { "ro.build.id", "engineering" }, + { "ro.build.date", "Wed Nov 28 07:44:14 PST 2007" }, + { "ro.build.date.utc", "1196264654" }, + { "ro.build.type", "eng" }, + { "ro.product.device", "simulator" /*"sooner"*/ }, + { "ro.product.brand", "generic" }, + { "ro.build.user", "fadden" }, + { "ro.build.host", "marathon" }, + { "ro.config.nocheckin", "yes" }, + { "ro.product.manufacturer", "" }, + { "ro.radio.use-ppp", "no" }, + { "ro.FOREGROUND_APP_ADJ", "0" }, + { "ro.VISIBLE_APP_ADJ", "1" }, + { "ro.SECONDARY_SERVER_ADJ", "2" }, + { "ro.HIDDEN_APP_MIN_ADJ", "7" }, + { "ro.CONTENT_PROVIDER_ADJ", "14" }, + { "ro.EMPTY_APP_ADJ", "15" }, + { "ro.FOREGROUND_APP_MEM", "1536" }, + { "ro.VISIBLE_APP_MEM", "2048" }, + { "ro.SECONDARY_SERVER_MEM", "4096" }, + { "ro.HIDDEN_APP_MEM", "8192" }, + { "ro.EMPTY_APP_MEM", "16384" }, + //{ "init.svc.adbd", "running" }, // causes ADB-JDWP + { "init.svc.usbd", "running" }, + { "init.svc.debuggerd", "running" }, + { "init.svc.ril-daemon", "running" }, + { "init.svc.zygote", "running" }, + { "init.svc.runtime", "running" }, + { "init.svc.dbus", "running" }, + { "init.svc.pppd_gprs", "running" }, + { "adb.connected", "0" }, + //{ "use-adb-networking", "1" }, + /* + { "status.battery.state", "Slow" }, + { "status.battery.level", "5" }, + { "status.battery.level_raw", "50" }, + { "status.battery.level_scale", "9" }, + */ + + /* disable the annoying setup wizard */ + { "app.setupwizard.disable", "1" }, + + /* Dalvik options, set by AndroidRuntime */ + { "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" }, + //{ "dalvik.vm.execution-mode", "int:portable" }, + { "dalvik.vm.enableassertions", "all" }, // -ea + { "dalvik.vm.dexopt-flags", "" }, // e.g. "v=a,o=v,m=n" + { "dalvik.vm.deadlock-predict", "off" }, // -Xdeadlockpredict + //{ "dalvik.vm.jniopts", "forcecopy" }, // -Xjniopts + { "log.redirect-stdio", "false" }, // -Xlog-stdio + + /* SurfaceFlinger options */ + { "debug.sf.nobootanimation", "1" }, + { "debug.sf.showupdates", "0" }, + { "debug.sf.showcpu", "0" }, + { "debug.sf.showbackground", "0" }, + { "debug.sf.showfps", "0" }, + }; + + for (int i = 0; i < NELEM(propList); i++) + SetProperty(propList[i].key, propList[i].value); + + Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); + bool doCheckJni = false; + + pPrefs->GetBool("check-jni", &doCheckJni); + if (doCheckJni) + SetProperty(kPropCheckJni, "1"); + else + SetProperty(kPropCheckJni, "0"); +} + +/* + * Get the value of a property. + * + * "valueBuf" must hold at least PROPERTY_VALUE_MAX bytes. + * + * Returns "true" if the property was found. + */ +bool PropertyServer::GetProperty(const char* key, char* valueBuf) +{ + typedef List<Property>::iterator PropIter; + + assert(key != NULL); + assert(valueBuf != NULL); + + for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) { + Property& prop = *pi; + if (strcmp(prop.key, key) == 0) { + if (strlen(prop.value) >= PROPERTY_VALUE_MAX) { + fprintf(stderr, + "GLITCH: properties table holds '%s' '%s' (len=%d)\n", + prop.key, prop.value, strlen(prop.value)); + abort(); + } + assert(strlen(prop.value) < PROPERTY_VALUE_MAX); + strcpy(valueBuf, prop.value); + return true; + } + } + + //printf("Prop: get [%s] not found\n", key); + return false; +} + +/* + * Set the value of a property, replacing it if it already exists. + * + * If "value" is NULL, the property is removed. + * + * If the property is immutable, this returns "false" without doing + * anything. (Not implemented.) + */ +bool PropertyServer::SetProperty(const char* key, const char* value) +{ + typedef List<Property>::iterator PropIter; + + assert(key != NULL); + assert(value != NULL); + + for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) { + Property& prop = *pi; + if (strcmp(prop.key, key) == 0) { + if (value != NULL) { + //printf("Prop: replacing [%s]: [%s] with [%s]\n", + // prop.key, prop.value, value); + strcpy(prop.value, value); + } else { + //printf("Prop: removing [%s]\n", prop.key); + mPropList.erase(pi); + } + return true; + } + } + + //printf("Prop: adding [%s]: [%s]\n", key, value); + Property tmp; + strcpy(tmp.key, key); + strcpy(tmp.value, value); + mPropList.push_back(tmp); + return true; +} + +/* + * Create a UNIX domain socket, carefully removing it if it already + * exists. + */ +bool PropertyServer::CreateSocket(const char* fileName) +{ + struct stat sb; + bool result = false; + int sock = -1; + int cc; + + cc = stat(fileName, &sb); + if (cc < 0) { + if (errno != ENOENT) { + LOG(LOG_ERROR, "sim-prop", + "Unable to stat '%s' (errno=%d)\n", fileName, errno); + goto bail; + } + } else { + /* don't touch it if it's not a socket */ + if (!(S_ISSOCK(sb.st_mode))) { + LOG(LOG_ERROR, "sim-prop", + "File '%s' exists and is not a socket\n", fileName); + goto bail; + } + + /* remove the cruft */ + if (unlink(fileName) < 0) { + LOG(LOG_ERROR, "sim-prop", + "Unable to remove '%s' (errno=%d)\n", fileName, errno); + goto bail; + } + } + + struct sockaddr_un addr; + + sock = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + LOG(LOG_ERROR, "sim-prop", + "UNIX domain socket create failed (errno=%d)\n", errno); + goto bail; + } + + /* bind the socket; this creates the file on disk */ + strcpy(addr.sun_path, fileName); // max 108 bytes + addr.sun_family = AF_UNIX; + cc = ::bind(sock, (struct sockaddr*) &addr, SUN_LEN(&addr)); + if (cc < 0) { + LOG(LOG_ERROR, "sim", + "AF_UNIX bind failed for '%s' (errno=%d)\n", fileName, errno); + goto bail; + } + + cc = ::listen(sock, 5); + if (cc < 0) { + LOG(LOG_ERROR, "sim", "AF_UNIX listen failed (errno=%d)\n", errno); + goto bail; + } + + mListenSock = sock; + sock = -1; + result = true; + +bail: + if (sock >= 0) + close(sock); + return result; +} + +/* + * Handle a client request. + * + * Returns true on success, false if the fd should be closed. + */ +bool PropertyServer::HandleRequest(int fd) +{ + char reqBuf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX]; + char valueBuf[1 + PROPERTY_VALUE_MAX]; + ssize_t actual; + + memset(valueBuf, 'x', sizeof(valueBuf)); // placate valgrind + + /* read the command byte; this determines the message length */ + actual = read(fd, reqBuf, 1); + if (actual <= 0) + return false; + + if (reqBuf[0] == kSystemPropertyGet) { + actual = read(fd, reqBuf, PROPERTY_KEY_MAX); + + if (actual != PROPERTY_KEY_MAX) { + fprintf(stderr, "Bad read on get: %d of %d\n", + actual, PROPERTY_KEY_MAX); + return false; + } + if (GetProperty(reqBuf, valueBuf+1)) + valueBuf[0] = 1; + else + valueBuf[0] = 0; + //printf("GET property [%s]: (found=%d) [%s]\n", + // reqBuf, valueBuf[0], valueBuf+1); + if (write(fd, valueBuf, sizeof(valueBuf)) != sizeof(valueBuf)) { + fprintf(stderr, "Bad write on get\n"); + return false; + } + } else if (reqBuf[0] == kSystemPropertySet) { + actual = read(fd, reqBuf, PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX); + if (actual != PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX) { + fprintf(stderr, "Bad read on set: %d of %d\n", + actual, PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX); + return false; + } + //printf("SET property '%s'\n", reqBuf); + if (SetProperty(reqBuf, reqBuf + PROPERTY_KEY_MAX)) + valueBuf[0] = 1; + else + valueBuf[0] = 0; + if (write(fd, valueBuf, 1) != 1) { + fprintf(stderr, "Bad write on set\n"); + return false; + } + } else if (reqBuf[0] == kSystemPropertyList) { + /* TODO */ + assert(false); + } else { + fprintf(stderr, "Unexpected request %d from prop client\n", reqBuf[0]); + return false; + } + + return true; +} + +/* + * Serve up properties. + */ +void PropertyServer::ServeProperties(void) +{ + typedef List<int>::iterator IntIter; + fd_set readfds; + int maxfd; + + while (true) { + int cc; + + FD_ZERO(&readfds); + FD_SET(mListenSock, &readfds); + maxfd = mListenSock; + + for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ++ii) { + int fd = (*ii); + + FD_SET(fd, &readfds); + if (maxfd < fd) + maxfd = fd; + } + + cc = select(maxfd+1, &readfds, NULL, NULL, NULL); + if (cc < 0) { + if (errno == EINTR) { + printf("hiccup!\n"); + continue; + } + return; + } + if (FD_ISSET(mListenSock, &readfds)) { + struct sockaddr_un from; + socklen_t fromlen; + int newSock; + + fromlen = sizeof(from); + newSock = ::accept(mListenSock, (struct sockaddr*) &from, &fromlen); + if (newSock < 0) { + LOG(LOG_WARN, "sim", + "AF_UNIX accept failed (errno=%d)\n", errno); + } else { + //printf("new props connection on %d --> %d\n", + // mListenSock, newSock); + + mClientList.push_back(newSock); + } + } + + for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ) { + int fd = (*ii); + bool ok = true; + + if (FD_ISSET(fd, &readfds)) { + //printf("--- activity on %d\n", fd); + + ok = HandleRequest(fd); + } + + if (ok) { + ++ii; + } else { + //printf("--- closing %d\n", fd); + close(fd); + ii = mClientList.erase(ii); + } + } + } +} + +/* + * Thread entry point. + * + * This just sits and waits for a new connection. It hands it off to the + * main thread and then goes back to waiting. + * + * There is currently no "polite" way to shut this down. + */ +void* PropertyServer::Entry(void) +{ + if (CreateSocket(SYSTEM_PROPERTY_PIPE_NAME)) { + assert(mListenSock >= 0); + SetDefaultProperties(); + + /* loop until it's time to exit or we fail */ + ServeProperties(); + + ClearProperties(); + + /* + * Close listen socket and all clients. + */ + LOG(LOG_INFO, "sim", "Cleaning up socket list\n"); + typedef List<int>::iterator IntIter; + for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ++ii) + close((*ii)); + close(mListenSock); + } + + LOG(LOG_INFO, "sim", "PropertyServer thread exiting\n"); + return NULL; +} + |
