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