• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
~PropertyServer(void)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  */
StartThread(void)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  */
ClearProperties(void)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  */
SetDefaultProperties(void)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  */
GetProperty(const char * key,char * valueBuf)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  */
SetProperty(const char * key,const char * value)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  */
CreateSocket(const char * fileName)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  */
HandleRequest(int fd)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  */
ServeProperties(void)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  */
Entry(void)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