• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* this program is used to read a set of system properties and their values
18  * from the emulator program and set them in the currently-running emulated
19  * system. It does so by connecting to the 'boot-properties' qemud service.
20  *
21  * This program should be run as root and called from
22  * /system/etc/init.goldfish.rc exclusively.
23  */
24 
25 #define LOG_TAG  "qemu-props"
26 
27 #define DEBUG  1
28 
29 #if DEBUG
30 #  include <log/log.h>
31 #  define  DD(...)    ALOGI(__VA_ARGS__)
32 #else
33 #  define  DD(...)    ((void)0)
34 #endif
35 
36 #include <cutils/properties.h>
37 #include <unistd.h>
38 #include "qemud.h"
39 
40 /* Name of the qemud service we want to connect to.
41  */
42 #define  QEMUD_SERVICE  "boot-properties"
43 
44 #define  MAX_TRIES      5
45 
46 #define QEMU_MISC_PIPE "QemuMiscPipe"
47 
48 int s_QemuMiscPipe = -1;
49 void static notifyHostBootComplete();
50 
main(void)51 int  main(void)
52 {
53     int  qemud_fd, count = 0;
54 
55     /* try to connect to the qemud service */
56     {
57         int  tries = MAX_TRIES;
58 
59         while (1) {
60             qemud_fd = qemud_channel_open( "boot-properties" );
61             if (qemud_fd >= 0)
62                 break;
63 
64             if (--tries <= 0) {
65                 DD("Could not connect after too many tries. Aborting");
66                 return 1;
67             }
68 
69             DD("waiting 1s to wait for qemud.");
70             sleep(1);
71         }
72     }
73 
74     DD("connected to '%s' qemud service.", QEMUD_SERVICE);
75 
76     /* send the 'list' command to the service */
77     if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
78         DD("could not send command to '%s' service", QEMUD_SERVICE);
79         return 1;
80     }
81 
82     /* read each system property as a single line from the service,
83      * until exhaustion.
84      */
85     for (;;)
86     {
87 #define  BUFF_SIZE   (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
88         DD("receiving..");
89         char* q;
90         char  temp[BUFF_SIZE];
91         char  vendortemp[BUFF_SIZE];
92         int   len = qemud_channel_recv(qemud_fd, temp, sizeof temp - 1);
93 
94         /* lone NUL-byte signals end of properties */
95         if (len < 0 || len > BUFF_SIZE-1 || temp[0] == '\0')
96             break;
97 
98         temp[len] = '\0';  /* zero-terminate string */
99 
100         DD("received: %.*s", len, temp);
101 
102         /* separate propery name from value */
103         q = strchr(temp, '=');
104         if (q == NULL) {
105             DD("invalid format, ignored.");
106             continue;
107         }
108         *q++ = '\0';
109 
110         char* final_prop_name = NULL;
111         if (strcmp(temp, "qemu.sf.lcd.density") == 0 ) {
112             final_prop_name = temp;
113         } else if (strcmp(temp, "qemu.hw.mainkeys") == 0 ) {
114             final_prop_name = temp;
115         } else if (strcmp(temp, "qemu.cmdline") == 0 ) {
116             final_prop_name = temp;
117         } else if (strcmp(temp, "dalvik.vm.heapsize") == 0 ) {
118             continue; /* cannot set it here */
119         } else if (strcmp(temp, "ro.opengles.version") == 0 ) {
120             continue; /* cannot set it here */
121         } else {
122             snprintf(vendortemp, sizeof(vendortemp), "vendor.%s", temp);
123             final_prop_name = vendortemp;
124         }
125         if (property_set(temp, q) < 0) {
126             ALOGW("could not set property '%s' to '%s'", final_prop_name, q);
127         } else {
128             ALOGI("successfully set property '%s' to '%s'", final_prop_name, q);
129             count += 1;
130         }
131     }
132 
133     char temp[BUFF_SIZE];
134     for (;;) {
135         usleep(5000000); /* 5 seconds */
136         property_get("vendor.qemu.dev.bootcomplete", temp, "");
137         int is_boot_completed = (strncmp(temp, "1", 1) == 0) ? 1 : 0;
138         if (is_boot_completed) {
139             ALOGI("tell the host boot completed");
140             notifyHostBootComplete();
141             break;
142         }
143     }
144 
145     /* finally, close the channel and exit */
146     if (s_QemuMiscPipe >= 0) {
147         close(s_QemuMiscPipe);
148         s_QemuMiscPipe = -1;
149     }
150     close(qemud_fd);
151     DD("exiting (%d properties set).", count);
152     return 0;
153 }
154 
notifyHostBootComplete()155 void notifyHostBootComplete() {
156    if (s_QemuMiscPipe < 0) {
157         s_QemuMiscPipe = qemu_pipe_open(QEMU_MISC_PIPE);
158         if (s_QemuMiscPipe < 0) {
159             ALOGE("failed to open %s", QEMU_MISC_PIPE);
160             return;
161         }
162     }
163     char set[] = "bootcomplete";
164     int pipe_command_length = sizeof(set);
165     WriteFully(s_QemuMiscPipe, &pipe_command_length, sizeof(pipe_command_length));
166     WriteFully(s_QemuMiscPipe, set, pipe_command_length);
167     ReadFully(s_QemuMiscPipe, &pipe_command_length, sizeof(pipe_command_length));
168     if (pipe_command_length > (int)(sizeof(set)) || pipe_command_length <= 0)
169         return;
170     ReadFully(s_QemuMiscPipe, set, pipe_command_length);
171 }
172