• 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.ranchu.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 <string_view>
37 #include <cutils/properties.h>
38 #include <unistd.h>
39 #include <qemu_pipe_bp.h>
40 #include <qemud.h>
41 #include <string.h>
42 #include <stdio.h>
43 
44 /* Name of the qemud service we want to connect to.
45  */
46 #define  QEMUD_SERVICE  "boot-properties"
47 
48 #define  MAX_TRIES      5
49 
50 #define QEMU_MISC_PIPE "QemuMiscPipe"
51 
52 namespace {
53 // qemu-props will not set these properties.
54 const char* const k_properties_to_ignore[] = {
55     "dalvik.vm.heapsize",
56     "ro.opengles.version",
57     "qemu.adb.secure",
58     nullptr,
59 };
60 
61 // These properties will not be prefixed with "vendor.".
62 const char* const k_system_properties[] = {
63     "qemu.sf.lcd_density",
64     "qemu.hw.mainkeys",
65     nullptr,
66 };
67 
check_if_property_in_list(const char * prop_name,const char * const * prop_list)68 bool check_if_property_in_list(const char* prop_name, const char* const* prop_list) {
69     for (; *prop_list; ++prop_list) {
70         if (!strcmp(prop_name, *prop_list)) {
71             return true;
72         }
73     }
74     return false;
75 }
76 
77 // We don't want to rename properties which already have the prefix
78 // or the system properties.
need_prepend_prefix(const char * prop,const std::string_view prefix)79 bool need_prepend_prefix(const char* prop, const std::string_view prefix) {
80     return strncmp(prefix.data(), prop, prefix.size()) &&
81            !check_if_property_in_list(prop, k_system_properties);
82 }
83 }  // namespace
84 
85 int s_QemuMiscPipe = -1;
86 void static notifyHostBootComplete();
87 void static sendHeartBeat();
88 void static sendMessage(const char* mesg);
89 void static closeMiscPipe();
90 extern void parse_virtio_serial();
91 
main(void)92 int main(void)
93 {
94     int  qemud_fd, count = 0;
95 
96     /* try to connect to the qemud service */
97     {
98         int  tries = MAX_TRIES;
99 
100         while (true) {
101             qemud_fd = qemud_channel_open( "boot-properties" );
102             if (qemud_fd >= 0)
103                 break;
104 
105             if (--tries <= 0) {
106                 DD("Could not connect after too many tries. Aborting");
107                 return 1;
108             }
109 
110             DD("waiting 1s to wait for qemud.");
111             sleep(1);
112         }
113     }
114 
115     DD("connected to '%s' qemud service.", QEMUD_SERVICE);
116 
117     /* send the 'list' command to the service */
118     if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
119         DD("could not send command to '%s' service", QEMUD_SERVICE);
120         return 1;
121     }
122 
123     /* read each system property as a single line from the service,
124      * until exhaustion.
125      */
126     while (true) {
127 #define  BUFF_SIZE   (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
128         DD("receiving..");
129         char* prop_value;
130         char  temp[BUFF_SIZE];
131         int   len = qemud_channel_recv(qemud_fd, temp, sizeof(temp) - 1);
132 
133         /* lone NUL-byte signals end of properties */
134         if (len < 0 || len > (BUFF_SIZE - 1) || !temp[0]) {
135             break;
136         }
137 
138         temp[len] = '\0';  /* zero-terminate string */
139 
140         DD("received: %.*s", len, temp);
141 
142         /* separate propery name from value */
143         prop_value = strchr(temp, '=');
144         if (!prop_value) {
145             DD("invalid format, ignored.");
146             continue;
147         }
148 
149         *prop_value = 0;
150         ++prop_value;
151 
152         if (check_if_property_in_list(temp, k_properties_to_ignore)) {
153             ALOGI("ignoring '%s' property", temp);
154             continue;   // do not set these
155         }
156 
157         char renamed_property[BUFF_SIZE];
158         const char* final_prop_name = nullptr;
159 
160         using namespace std::literals;
161         static constexpr std::string_view k_vendor_prefix = "vendor."sv;
162         if (need_prepend_prefix(temp, k_vendor_prefix)) {
163             snprintf(renamed_property, sizeof(renamed_property), "%.*s%s",
164                      int(k_vendor_prefix.size()), k_vendor_prefix.data(), temp);
165 
166             final_prop_name = renamed_property;
167         } else {
168             final_prop_name = temp;
169         }
170 
171         if (property_set(final_prop_name, prop_value) < 0) {
172             ALOGW("could not set property '%s' to '%s'", final_prop_name, prop_value);
173         } else {
174             ALOGI("successfully set property '%s' to '%s'", final_prop_name, prop_value);
175             count += 1;
176         }
177     }
178 
179     close(qemud_fd);
180 
181     parse_virtio_serial();
182 
183     char temp[BUFF_SIZE];
184     sendHeartBeat();
185     while (s_QemuMiscPipe >= 0) {
186         usleep(5000000); /* 5 seconds */
187         sendHeartBeat();
188         property_get("vendor.qemu.dev.bootcomplete", temp, "");
189         int is_boot_completed = (strncmp(temp, "1", 1) == 0) ? 1 : 0;
190         if (is_boot_completed) {
191             ALOGI("tell the host boot completed");
192             notifyHostBootComplete();
193             break;
194         }
195     }
196 
197     while (s_QemuMiscPipe >= 0) {
198         usleep(30*1000000); /* 30 seconds */
199         sendHeartBeat();
200     }
201 
202     /* finally, close the channel and exit */
203     closeMiscPipe();
204     DD("exiting (%d properties set).", count);
205     return 0;
206 }
207 
sendHeartBeat()208 void sendHeartBeat() {
209     sendMessage("heartbeat");
210 }
211 
notifyHostBootComplete()212 void notifyHostBootComplete() {
213     sendMessage("bootcomplete");
214 }
215 
sendMessage(const char * mesg)216 void sendMessage(const char* mesg) {
217    if (s_QemuMiscPipe < 0) {
218         s_QemuMiscPipe = qemu_pipe_open_ns(NULL, QEMU_MISC_PIPE, O_RDWR);
219         if (s_QemuMiscPipe < 0) {
220             ALOGE("failed to open %s", QEMU_MISC_PIPE);
221             return;
222         }
223     }
224 
225     int32_t cmd_len = strlen(mesg) + 1; //including trailing '\0'
226     qemu_pipe_write_fully(s_QemuMiscPipe, &cmd_len, sizeof(cmd_len));
227     qemu_pipe_write_fully(s_QemuMiscPipe, mesg, cmd_len);
228 
229     int r = qemu_pipe_read_fully(s_QemuMiscPipe, &cmd_len, sizeof(cmd_len));
230     if (r || (cmd_len < 0)) {
231         closeMiscPipe();
232         return;
233     }
234 
235     while (cmd_len > 0) {
236         char buf[64];
237         const size_t chunk = std::min<size_t>(cmd_len, sizeof(buf));
238         r = qemu_pipe_read_fully(s_QemuMiscPipe, buf, chunk);
239         if (r) {
240             closeMiscPipe();
241             return;
242         } else {
243             cmd_len -= chunk;
244         }
245     }
246 }
247 
closeMiscPipe()248 void closeMiscPipe() {
249     if (s_QemuMiscPipe >= 0) {
250         close(s_QemuMiscPipe);
251         s_QemuMiscPipe = -1;
252     }
253 }
254