Home | History | Annotate | Download | only in app
      1 //
      2 // Copyright 2007 The Android Open Source Project
      3 //
      4 // Property sever.  Mimics behavior provided on the device by init(8) and
      5 // some code built into libc.
      6 //
      7 
      8 // For compilers that support precompilation, include "wx/wx.h".
      9 #include "wx/wxprec.h"
     10 
     11 // Otherwise, include all standard headers
     12 #ifndef WX_PRECOMP
     13 # include "wx/wx.h"
     14 #endif
     15 #include "wx/image.h"
     16 
     17 #include "PropertyServer.h"
     18 #include "MyApp.h"
     19 #include "Preferences.h"
     20 #include "MainFrame.h"
     21 #include "utils.h"
     22 
     23 #include <stdlib.h>
     24 #include <unistd.h>
     25 #include <string.h>
     26 #include <errno.h>
     27 #include <assert.h>
     28 #include <sys/types.h>
     29 #include <sys/socket.h>
     30 #include <sys/stat.h>
     31 #include <sys/un.h>
     32 
     33 
     34 using namespace android;
     35 
     36 const char* PropertyServer::kPropCheckJni = "ro.kernel.android.checkjni";
     37 
     38 /*
     39  * Destructor.
     40  */
     41 PropertyServer::~PropertyServer(void)
     42 {
     43     if (IsRunning()) {
     44         // TODO: cause thread to stop, then Wait for it
     45     }
     46     printf("Sim: in ~PropertyServer()\n");
     47 }
     48 
     49 /*
     50  * Create and run the thread.
     51  */
     52 bool PropertyServer::StartThread(void)
     53 {
     54     if (Create() != wxTHREAD_NO_ERROR) {
     55         fprintf(stderr, "Sim: ERROR: can't create PropertyServer thread\n");
     56         return false;
     57     }
     58 
     59     Run();
     60     return true;
     61 }
     62 
     63 
     64 /*
     65  * Clear out the list.
     66  */
     67 void PropertyServer::ClearProperties(void)
     68 {
     69     typedef List<Property>::iterator PropIter;
     70 
     71     for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) {
     72         pi = mPropList.erase(pi);
     73     }
     74 }
     75 
     76 /*
     77  * Set default values for several properties.
     78  */
     79 void PropertyServer::SetDefaultProperties(void)
     80 {
     81     static const struct {
     82         const char* key;
     83         const char* value;
     84     } propList[] = {
     85         { "net.bt.name", "Android" },
     86         { "ro.kernel.mem", "60M" },
     87         { "ro.kernel.board_sardine.version", "4" },
     88         { "ro.kernel.console", "null" },
     89         { "ro.build.id", "engineering" },
     90         { "ro.build.date", "Wed Nov 28 07:44:14 PST 2007" },
     91         { "ro.build.date.utc", "1196264654" },
     92         { "ro.build.type", "eng" },
     93         { "ro.product.device", "simulator" /*"sooner"*/ },
     94         { "ro.product.brand", "generic" },
     95         { "ro.build.user", "fadden" },
     96         { "ro.build.host", "marathon" },
     97         { "ro.config.nocheckin", "yes" },
     98         { "ro.product.manufacturer", "" },
     99         { "ro.radio.use-ppp", "no" },
    100         { "ro.FOREGROUND_APP_ADJ", "0" },
    101         { "ro.VISIBLE_APP_ADJ", "1" },
    102         { "ro.SECONDARY_SERVER_ADJ", "2" },
    103         { "ro.HIDDEN_APP_MIN_ADJ", "7" },
    104         { "ro.CONTENT_PROVIDER_ADJ", "14" },
    105         { "ro.EMPTY_APP_ADJ", "15" },
    106         { "ro.FOREGROUND_APP_MEM", "1536" },
    107         { "ro.VISIBLE_APP_MEM", "2048" },
    108         { "ro.SECONDARY_SERVER_MEM", "4096" },
    109         { "ro.HIDDEN_APP_MEM", "8192" },
    110         { "ro.EMPTY_APP_MEM", "16384" },
    111         { "ro.HOME_APP_ADJ", "4" },
    112         { "ro.HOME_APP_MEM", "4096" },
    113         { "ro.BACKUP_APP_ADJ", "2" },
    114         { "ro.BACKUP_APP_MEM", "4096" },
    115         { "ro.PERCEPTIBLE_APP_ADJ", "2" },
    116         { "ro.PERCEPTIBLE_APP_MEM", "4096" },
    117         { "ro.HEAVY_WEIGHT_APP_ADJ", "3" },
    118         { "ro.HEAVY_WEIGHT_APP_MEM", "4096" },
    119         //{ "init.svc.adbd", "running" },       // causes ADB-JDWP
    120         { "init.svc.usbd", "running" },
    121         { "init.svc.debuggerd", "running" },
    122         { "init.svc.ril-daemon", "running" },
    123         { "init.svc.zygote", "running" },
    124         { "init.svc.runtime", "running" },
    125         { "init.svc.dbus", "running" },
    126         { "init.svc.pppd_gprs", "running" },
    127         { "adb.connected", "0" },
    128         /*
    129         { "status.battery.state", "Slow" },
    130         { "status.battery.level", "5" },
    131         { "status.battery.level_raw", "50" },
    132         { "status.battery.level_scale", "9" },
    133         */
    134 
    135         /* disable the annoying setup wizard */
    136         { "app.setupwizard.disable", "1" },
    137 
    138         /* Dalvik options, set by AndroidRuntime */
    139         { "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" },
    140         //{ "dalvik.vm.execution-mode", "int:portable" },
    141         { "dalvik.vm.enableassertions", "all" },    // -ea
    142         { "dalvik.vm.dexopt-flags", "" },           // e.g. "v=a,o=v,m=n"
    143         { "dalvik.vm.deadlock-predict", "off" },    // -Xdeadlockpredict
    144         //{ "dalvik.vm.jniopts", "forcecopy" },       // -Xjniopts
    145         { "log.redirect-stdio", "false" },          // -Xlog-stdio
    146 
    147         /* SurfaceFlinger options */
    148         { "debug.sf.nobootanimation", "1" },
    149         { "debug.sf.showupdates", "0" },
    150         { "debug.sf.showcpu", "0" },
    151         { "debug.sf.showbackground", "0" },
    152         { "debug.sf.showfps", "0" },
    153         { "default", "default" },
    154 
    155         /* Stagefright options */
    156         { "media.stagefright.enable-player", "true" },
    157         { "media.stagefright.enable-meta", "true" },
    158         { "media.stagefright.enable-scan", "true" },
    159         { "media.stagefright.enable-http", "true" },
    160     };
    161 
    162     for (int i = 0; i < NELEM(propList); i++)
    163         SetProperty(propList[i].key, propList[i].value);
    164 
    165     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
    166     bool doCheckJni = false;
    167 
    168     pPrefs->GetBool("check-jni", &doCheckJni);
    169     if (doCheckJni)
    170         SetProperty(kPropCheckJni, "1");
    171     else
    172         SetProperty(kPropCheckJni, "0");
    173 }
    174 
    175 /*
    176  * Get the value of a property.
    177  *
    178  * "valueBuf" must hold at least PROPERTY_VALUE_MAX bytes.
    179  *
    180  * Returns "true" if the property was found.
    181  */
    182 bool PropertyServer::GetProperty(const char* key, char* valueBuf)
    183 {
    184     typedef List<Property>::iterator PropIter;
    185 
    186     assert(key != NULL);
    187     assert(valueBuf != NULL);
    188 
    189     for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) {
    190         Property& prop = *pi;
    191         if (strcmp(prop.key, key) == 0) {
    192             if (strlen(prop.value) >= PROPERTY_VALUE_MAX) {
    193                 fprintf(stderr,
    194                     "GLITCH: properties table holds '%s' '%s' (len=%d)\n",
    195                     prop.key, prop.value, (int) strlen(prop.value));
    196                 abort();
    197             }
    198             assert(strlen(prop.value) < PROPERTY_VALUE_MAX);
    199             strcpy(valueBuf, prop.value);
    200             return true;
    201         }
    202     }
    203 
    204     //printf("Prop: get [%s] not found\n", key);
    205     return false;
    206 }
    207 
    208 /*
    209  * Set the value of a property, replacing it if it already exists.
    210  *
    211  * If "value" is NULL, the property is removed.
    212  *
    213  * If the property is immutable, this returns "false" without doing
    214  * anything.  (Not implemented.)
    215  */
    216 bool PropertyServer::SetProperty(const char* key, const char* value)
    217 {
    218     typedef List<Property>::iterator PropIter;
    219 
    220     assert(key != NULL);
    221     assert(value != NULL);
    222 
    223     for (PropIter pi = mPropList.begin(); pi != mPropList.end(); ++pi) {
    224         Property& prop = *pi;
    225         if (strcmp(prop.key, key) == 0) {
    226             if (value != NULL) {
    227                 //printf("Prop: replacing [%s]: [%s] with [%s]\n",
    228                 //    prop.key, prop.value, value);
    229                 strcpy(prop.value, value);
    230             } else {
    231                 //printf("Prop: removing [%s]\n", prop.key);
    232                 mPropList.erase(pi);
    233             }
    234             return true;
    235         }
    236     }
    237 
    238     //printf("Prop: adding [%s]: [%s]\n", key, value);
    239     Property tmp;
    240     strcpy(tmp.key, key);
    241     strcpy(tmp.value, value);
    242     mPropList.push_back(tmp);
    243     return true;
    244 }
    245 
    246 /*
    247  * Create a UNIX domain socket, carefully removing it if it already
    248  * exists.
    249  */
    250 bool PropertyServer::CreateSocket(const char* fileName)
    251 {
    252     struct stat sb;
    253     bool result = false;
    254     int sock = -1;
    255     int cc;
    256 
    257     cc = stat(fileName, &sb);
    258     if (cc < 0) {
    259         if (errno != ENOENT) {
    260             LOG(LOG_ERROR, "sim-prop",
    261                 "Unable to stat '%s' (errno=%d)\n", fileName, errno);
    262             goto bail;
    263         }
    264     } else {
    265         /* don't touch it if it's not a socket */
    266         if (!(S_ISSOCK(sb.st_mode))) {
    267             LOG(LOG_ERROR, "sim-prop",
    268                 "File '%s' exists and is not a socket\n", fileName);
    269             goto bail;
    270         }
    271 
    272         /* remove the cruft */
    273         if (unlink(fileName) < 0) {
    274             LOG(LOG_ERROR, "sim-prop",
    275                 "Unable to remove '%s' (errno=%d)\n", fileName, errno);
    276             goto bail;
    277         }
    278     }
    279 
    280     struct sockaddr_un addr;
    281 
    282     sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
    283     if (sock < 0) {
    284         LOG(LOG_ERROR, "sim-prop",
    285             "UNIX domain socket create failed (errno=%d)\n", errno);
    286         goto bail;
    287     }
    288 
    289     /* bind the socket; this creates the file on disk */
    290     strcpy(addr.sun_path, fileName);    // max 108 bytes
    291     addr.sun_family = AF_UNIX;
    292     cc = ::bind(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
    293     if (cc < 0) {
    294         LOG(LOG_ERROR, "sim",
    295             "AF_UNIX bind failed for '%s' (errno=%d)\n", fileName, errno);
    296         goto bail;
    297     }
    298 
    299     cc = ::listen(sock, 5);
    300     if (cc < 0) {
    301         LOG(LOG_ERROR, "sim", "AF_UNIX listen failed (errno=%d)\n", errno);
    302         goto bail;
    303     }
    304 
    305     mListenSock = sock;
    306     sock = -1;
    307     result = true;
    308 
    309 bail:
    310     if (sock >= 0)
    311         close(sock);
    312     return result;
    313 }
    314 
    315 /*
    316  * Handle a client request.
    317  *
    318  * Returns true on success, false if the fd should be closed.
    319  */
    320 bool PropertyServer::HandleRequest(int fd)
    321 {
    322     char reqBuf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX];
    323     char valueBuf[1 + PROPERTY_VALUE_MAX];
    324     ssize_t actual;
    325 
    326     memset(valueBuf, 'x', sizeof(valueBuf));        // placate valgrind
    327 
    328     /* read the command byte; this determines the message length */
    329     actual = read(fd, reqBuf, 1);
    330     if (actual <= 0)
    331         return false;
    332 
    333     if (reqBuf[0] == kSystemPropertyGet) {
    334         actual = read(fd, reqBuf, PROPERTY_KEY_MAX);
    335 
    336         if (actual != PROPERTY_KEY_MAX) {
    337             fprintf(stderr, "Bad read on get: %d of %d\n",
    338                 (int) actual, PROPERTY_KEY_MAX);
    339             return false;
    340         }
    341         if (GetProperty(reqBuf, valueBuf+1))
    342             valueBuf[0] = 1;
    343         else
    344             valueBuf[0] = 0;
    345         //printf("GET property [%s]: (found=%d) [%s]\n",
    346         //    reqBuf, valueBuf[0], valueBuf+1);
    347         if (write(fd, valueBuf, sizeof(valueBuf)) != sizeof(valueBuf)) {
    348             fprintf(stderr, "Bad write on get\n");
    349             return false;
    350         }
    351     } else if (reqBuf[0] == kSystemPropertySet) {
    352         actual = read(fd, reqBuf, PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX);
    353         if (actual != PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX) {
    354             fprintf(stderr, "Bad read on set: %d of %d\n",
    355                 (int) actual, PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX);
    356             return false;
    357         }
    358         //printf("SET property '%s'\n", reqBuf);
    359         if (SetProperty(reqBuf, reqBuf + PROPERTY_KEY_MAX))
    360             valueBuf[0] = 1;
    361         else
    362             valueBuf[0] = 0;
    363         if (write(fd, valueBuf, 1) != 1) {
    364             fprintf(stderr, "Bad write on set\n");
    365             return false;
    366         }
    367     } else if (reqBuf[0] == kSystemPropertyList) {
    368         /* TODO */
    369         assert(false);
    370     } else {
    371         fprintf(stderr, "Unexpected request %d from prop client\n", reqBuf[0]);
    372         return false;
    373     }
    374 
    375     return true;
    376 }
    377 
    378 /*
    379  * Serve up properties.
    380  */
    381 void PropertyServer::ServeProperties(void)
    382 {
    383     typedef List<int>::iterator IntIter;
    384     fd_set readfds;
    385     int maxfd;
    386 
    387     while (true) {
    388         int cc;
    389 
    390         FD_ZERO(&readfds);
    391         FD_SET(mListenSock, &readfds);
    392         maxfd = mListenSock;
    393 
    394         for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ++ii) {
    395             int fd = (*ii);
    396 
    397             FD_SET(fd, &readfds);
    398             if (maxfd < fd)
    399                 maxfd = fd;
    400         }
    401 
    402         cc = select(maxfd+1, &readfds, NULL, NULL, NULL);
    403         if (cc < 0) {
    404             if (errno == EINTR) {
    405                 printf("hiccup!\n");
    406                 continue;
    407             }
    408             return;
    409         }
    410         if (FD_ISSET(mListenSock, &readfds)) {
    411             struct sockaddr_un from;
    412             socklen_t fromlen;
    413             int newSock;
    414 
    415             fromlen = sizeof(from);
    416             newSock = ::accept(mListenSock, (struct sockaddr*) &from, &fromlen);
    417             if (newSock < 0) {
    418                 LOG(LOG_WARN, "sim",
    419                     "AF_UNIX accept failed (errno=%d)\n", errno);
    420             } else {
    421                 //printf("new props connection on %d --> %d\n",
    422                 //    mListenSock, newSock);
    423 
    424                 mClientList.push_back(newSock);
    425             }
    426         }
    427 
    428         for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ) {
    429             int fd = (*ii);
    430             bool ok = true;
    431 
    432             if (FD_ISSET(fd, &readfds)) {
    433                 //printf("--- activity on %d\n", fd);
    434 
    435                 ok = HandleRequest(fd);
    436             }
    437 
    438             if (ok) {
    439                 ++ii;
    440             } else {
    441                 //printf("--- closing %d\n", fd);
    442                 close(fd);
    443                 ii = mClientList.erase(ii);
    444             }
    445         }
    446     }
    447 }
    448 
    449 /*
    450  * Thread entry point.
    451  *
    452  * This just sits and waits for a new connection.  It hands it off to the
    453  * main thread and then goes back to waiting.
    454  *
    455  * There is currently no "polite" way to shut this down.
    456  */
    457 void* PropertyServer::Entry(void)
    458 {
    459     if (CreateSocket(SYSTEM_PROPERTY_PIPE_NAME)) {
    460         assert(mListenSock >= 0);
    461         SetDefaultProperties();
    462 
    463         /* loop until it's time to exit or we fail */
    464         ServeProperties();
    465 
    466         ClearProperties();
    467 
    468         /*
    469          * Close listen socket and all clients.
    470          */
    471         LOG(LOG_INFO, "sim", "Cleaning up socket list\n");
    472         typedef List<int>::iterator IntIter;
    473         for (IntIter ii = mClientList.begin(); ii != mClientList.end(); ++ii)
    474             close((*ii));
    475         close(mListenSock);
    476     }
    477 
    478     LOG(LOG_INFO, "sim", "PropertyServer thread exiting\n");
    479     return NULL;
    480 }
    481 
    482