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