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 #include <string_view>
26 #include <android-base/unique_fd.h>
27 #include <cutils/properties.h>
28 #include <unistd.h>
29 #include <qemu_pipe_bp.h>
30 #include <qemud.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <debug.h>
34
35 namespace {
36 constexpr char kBootPropertiesService[] = "boot-properties";
37 constexpr char kHeartbeatService[] = "QemuMiscPipe";
38
39 // qemu-props will not set these properties.
40 const char* const k_properties_to_ignore[] = {
41 "dalvik.vm.heapsize",
42 "ro.opengles.version",
43 "qemu.adb.secure",
44 nullptr,
45 };
46
47 // These properties will not be prefixed with "vendor.".
48 const char* const k_system_properties[] = {
49 "qemu.sf.lcd_density",
50 "qemu.hw.mainkeys",
51 nullptr,
52 };
53
check_if_property_in_list(const char * prop_name,const char * const * prop_list)54 bool check_if_property_in_list(const char* prop_name, const char* const* prop_list) {
55 for (; *prop_list; ++prop_list) {
56 if (!strcmp(prop_name, *prop_list)) {
57 return true;
58 }
59 }
60 return false;
61 }
62
63 // We don't want to rename properties which already have the prefix
64 // or the system properties.
need_prepend_prefix(const char * prop,const std::string_view prefix)65 bool need_prepend_prefix(const char* prop, const std::string_view prefix) {
66 return strncmp(prefix.data(), prop, prefix.size()) &&
67 !check_if_property_in_list(prop, k_system_properties);
68 }
69
70 // Deprecated, consider replacing with androidboot
setBootProperties()71 int setBootProperties() {
72 using android::base::unique_fd;
73 unique_fd qemud;
74
75 for (int tries = 5; tries > 0; --tries) {
76 qemud = unique_fd(qemud_channel_open(kBootPropertiesService));
77 if (qemud.ok()) {
78 break;
79 } else if (tries > 1) {
80 sleep(1);
81 } else {
82 return FAILURE(1);
83 }
84 }
85
86 if (qemud_channel_send(qemud.get(), "list", -1) < 0) {
87 return FAILURE(1);
88 }
89
90 while (true) {
91 char temp[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2];
92 const int len = qemud_channel_recv(qemud.get(), temp, sizeof(temp) - 1);
93
94 /* lone NUL-byte signals end of properties */
95 if (len < 0 || len > (sizeof(temp) - 1) || !temp[0]) {
96 break;
97 }
98
99 temp[len] = '\0';
100 char* prop_value = strchr(temp, '=');
101 if (!prop_value) {
102 continue;
103 }
104
105 *prop_value = 0;
106 ++prop_value;
107
108 if (check_if_property_in_list(temp, k_properties_to_ignore)) {
109 continue;
110 }
111
112 char renamed_property[sizeof(temp)];
113 const char* final_prop_name = nullptr;
114
115 using namespace std::literals;
116 static constexpr std::string_view k_vendor_prefix = "vendor."sv;
117 if (need_prepend_prefix(temp, k_vendor_prefix)) {
118 snprintf(renamed_property, sizeof(renamed_property), "%.*s%s",
119 int(k_vendor_prefix.size()), k_vendor_prefix.data(), temp);
120
121 final_prop_name = renamed_property;
122 } else {
123 final_prop_name = temp;
124 }
125
126 if (property_set(final_prop_name, prop_value) < 0) {
127 ALOGW("could not set property '%s' to '%s'", final_prop_name, prop_value);
128 } else {
129 ALOGI("successfully set property '%s' to '%s'", final_prop_name, prop_value);
130 }
131 }
132
133 return 0;
134 }
135
136 } // namespace
137
138 static int s_QemuMiscPipe = -1;
139 static void sendHeartBeat();
140 static void sendMessage(const char* mesg);
141 static void closeMiscPipe();
142 extern void parse_virtio_serial();
143
main(const int argc,const char * argv[])144 int main(const int argc, const char* argv[])
145 {
146 if ((argc == 2) && !strcmp(argv[1], "bootcomplete")) {
147 sendMessage("bootcomplete");
148 return 0;
149 }
150
151 int r = setBootProperties();
152 if (r) {
153 return r;
154 }
155
156 parse_virtio_serial();
157
158 sendHeartBeat();
159 while (s_QemuMiscPipe >= 0) {
160 usleep(5000000); /* 5 seconds */
161 sendHeartBeat();
162 char temp[PROPERTY_VALUE_MAX];
163 property_get("vendor.qemu.dev.bootcomplete", temp, "");
164 if (strcmp(temp, "1") == 0) {
165 break;
166 }
167 }
168
169 while (s_QemuMiscPipe >= 0) {
170 usleep(30 * 1000000);
171 sendHeartBeat();
172 }
173
174 closeMiscPipe();
175 return 0;
176 }
177
sendHeartBeat()178 void sendHeartBeat() {
179 sendMessage("heartbeat");
180 }
181
sendMessage(const char * mesg)182 void sendMessage(const char* mesg) {
183 if (s_QemuMiscPipe < 0) {
184 s_QemuMiscPipe = qemu_pipe_open_ns(NULL, kHeartbeatService, O_RDWR);
185 if (s_QemuMiscPipe < 0) {
186 ALOGE("failed to open %s", kHeartbeatService);
187 return;
188 }
189 }
190
191 int32_t cmd_len = strlen(mesg) + 1; //including trailing '\0'
192 qemu_pipe_write_fully(s_QemuMiscPipe, &cmd_len, sizeof(cmd_len));
193 qemu_pipe_write_fully(s_QemuMiscPipe, mesg, cmd_len);
194
195 int r = qemu_pipe_read_fully(s_QemuMiscPipe, &cmd_len, sizeof(cmd_len));
196 if (r || (cmd_len < 0)) {
197 closeMiscPipe();
198 return;
199 }
200
201 while (cmd_len > 0) {
202 char buf[64];
203 const size_t chunk = std::min<size_t>(cmd_len, sizeof(buf));
204 r = qemu_pipe_read_fully(s_QemuMiscPipe, buf, chunk);
205 if (r) {
206 closeMiscPipe();
207 return;
208 } else {
209 cmd_len -= chunk;
210 }
211 }
212 }
213
closeMiscPipe()214 void closeMiscPipe() {
215 if (s_QemuMiscPipe >= 0) {
216 close(s_QemuMiscPipe);
217 s_QemuMiscPipe = -1;
218 }
219 }
220