Home | History | Annotate | Download | only in init
      1 /*
      2  * Copyright (C) 2007 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 #include "property_service.h"
     18 
     19 #include <ctype.h>
     20 #include <dirent.h>
     21 #include <errno.h>
     22 #include <fcntl.h>
     23 #include <inttypes.h>
     24 #include <limits.h>
     25 #include <netinet/in.h>
     26 #include <stdarg.h>
     27 #include <stddef.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <sys/mman.h>
     32 #include <sys/poll.h>
     33 #include <sys/select.h>
     34 #include <sys/types.h>
     35 #include <sys/un.h>
     36 #include <unistd.h>
     37 
     38 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
     39 #include <sys/_system_properties.h>
     40 
     41 #include <memory>
     42 #include <queue>
     43 #include <vector>
     44 
     45 #include <android-base/chrono_utils.h>
     46 #include <android-base/file.h>
     47 #include <android-base/logging.h>
     48 #include <android-base/properties.h>
     49 #include <android-base/strings.h>
     50 #include <bootimg.h>
     51 #include <fs_mgr.h>
     52 #include <selinux/android.h>
     53 #include <selinux/label.h>
     54 #include <selinux/selinux.h>
     55 
     56 #include "init.h"
     57 #include "util.h"
     58 
     59 using android::base::Timer;
     60 
     61 #define PERSISTENT_PROPERTY_DIR  "/data/property"
     62 #define RECOVERY_MOUNT_POINT "/recovery"
     63 
     64 namespace android {
     65 namespace init {
     66 
     67 static int persistent_properties_loaded = 0;
     68 
     69 static int property_set_fd = -1;
     70 
     71 void property_init() {
     72     if (__system_property_area_init()) {
     73         LOG(ERROR) << "Failed to initialize property area";
     74         exit(1);
     75     }
     76 }
     77 
     78 static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
     79 
     80     if (!sctx) {
     81       return false;
     82     }
     83 
     84     if (!sehandle_prop) {
     85       return false;
     86     }
     87 
     88     char* tctx = nullptr;
     89     if (selabel_lookup(sehandle_prop, &tctx, name.c_str(), 1) != 0) {
     90       return false;
     91     }
     92 
     93     property_audit_data audit_data;
     94 
     95     audit_data.name = name.c_str();
     96     audit_data.cr = cr;
     97 
     98     bool has_access = (selinux_check_access(sctx, tctx, "property_service", "set", &audit_data) == 0);
     99 
    100     freecon(tctx);
    101     return has_access;
    102 }
    103 
    104 static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
    105 {
    106     /*
    107      *  Create a name prefix out of ctl.<service name>
    108      *  The new prefix allows the use of the existing
    109      *  property service backend labeling while avoiding
    110      *  mislabels based on true property prefixes.
    111      */
    112     char ctl_name[PROP_VALUE_MAX+4];
    113     int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);
    114 
    115     if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
    116         return 0;
    117 
    118     return check_mac_perms(ctl_name, sctx, cr);
    119 }
    120 
    121 static void write_persistent_property(const char *name, const char *value)
    122 {
    123     char tempPath[PATH_MAX];
    124     char path[PATH_MAX];
    125     int fd;
    126 
    127     snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
    128     fd = mkstemp(tempPath);
    129     if (fd < 0) {
    130         PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath;
    131         return;
    132     }
    133     write(fd, value, strlen(value));
    134     fsync(fd);
    135     close(fd);
    136 
    137     snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
    138     if (rename(tempPath, path)) {
    139         PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path;
    140         unlink(tempPath);
    141     }
    142 }
    143 
    144 bool is_legal_property_name(const std::string& name) {
    145     size_t namelen = name.size();
    146 
    147     if (namelen < 1) return false;
    148     if (name[0] == '.') return false;
    149     if (name[namelen - 1] == '.') return false;
    150 
    151     /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
    152     /* Don't allow ".." to appear in a property name */
    153     for (size_t i = 0; i < namelen; i++) {
    154         if (name[i] == '.') {
    155             // i=0 is guaranteed to never have a dot. See above.
    156             if (name[i-1] == '.') return false;
    157             continue;
    158         }
    159         if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue;
    160         if (name[i] >= 'a' && name[i] <= 'z') continue;
    161         if (name[i] >= 'A' && name[i] <= 'Z') continue;
    162         if (name[i] >= '0' && name[i] <= '9') continue;
    163         return false;
    164     }
    165 
    166     return true;
    167 }
    168 
    169 static uint32_t PropertySetImpl(const std::string& name, const std::string& value) {
    170     size_t valuelen = value.size();
    171 
    172     if (!is_legal_property_name(name)) {
    173         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
    174         return PROP_ERROR_INVALID_NAME;
    175     }
    176 
    177     if (valuelen >= PROP_VALUE_MAX) {
    178         LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
    179                    << "value too long";
    180         return PROP_ERROR_INVALID_VALUE;
    181     }
    182 
    183     prop_info* pi = (prop_info*) __system_property_find(name.c_str());
    184     if (pi != nullptr) {
    185         // ro.* properties are actually "write-once".
    186         if (android::base::StartsWith(name, "ro.")) {
    187             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
    188                        << "property already set";
    189             return PROP_ERROR_READ_ONLY_PROPERTY;
    190         }
    191 
    192         __system_property_update(pi, value.c_str(), valuelen);
    193     } else {
    194         int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
    195         if (rc < 0) {
    196             LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
    197                        << "__system_property_add failed";
    198             return PROP_ERROR_SET_FAILED;
    199         }
    200     }
    201 
    202     // Don't write properties to disk until after we have read all default
    203     // properties to prevent them from being overwritten by default values.
    204     if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
    205         write_persistent_property(name.c_str(), value.c_str());
    206     }
    207     property_changed(name, value);
    208     return PROP_SUCCESS;
    209 }
    210 
    211 typedef int (*PropertyAsyncFunc)(const std::string&, const std::string&);
    212 
    213 struct PropertyChildInfo {
    214     pid_t pid;
    215     PropertyAsyncFunc func;
    216     std::string name;
    217     std::string value;
    218 };
    219 
    220 static std::queue<PropertyChildInfo> property_children;
    221 
    222 static void PropertyChildLaunch() {
    223     auto& info = property_children.front();
    224     pid_t pid = fork();
    225     if (pid < 0) {
    226         LOG(ERROR) << "Failed to fork for property_set_async";
    227         while (!property_children.empty()) {
    228             property_children.pop();
    229         }
    230         return;
    231     }
    232     if (pid != 0) {
    233         info.pid = pid;
    234     } else {
    235         if (info.func(info.name, info.value) != 0) {
    236             LOG(ERROR) << "property_set_async(\"" << info.name << "\", \"" << info.value
    237                        << "\") failed";
    238         }
    239         exit(0);
    240     }
    241 }
    242 
    243 bool PropertyChildReap(pid_t pid) {
    244     if (property_children.empty()) {
    245         return false;
    246     }
    247     auto& info = property_children.front();
    248     if (info.pid != pid) {
    249         return false;
    250     }
    251     if (PropertySetImpl(info.name, info.value) != PROP_SUCCESS) {
    252         LOG(ERROR) << "Failed to set async property " << info.name;
    253     }
    254     property_children.pop();
    255     if (!property_children.empty()) {
    256         PropertyChildLaunch();
    257     }
    258     return true;
    259 }
    260 
    261 static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
    262                                  PropertyAsyncFunc func) {
    263     if (value.empty()) {
    264         return PropertySetImpl(name, value);
    265     }
    266 
    267     PropertyChildInfo info;
    268     info.func = func;
    269     info.name = name;
    270     info.value = value;
    271     property_children.push(info);
    272     if (property_children.size() == 1) {
    273         PropertyChildLaunch();
    274     }
    275     return PROP_SUCCESS;
    276 }
    277 
    278 static int RestoreconRecursiveAsync(const std::string& name, const std::string& value) {
    279     return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
    280 }
    281 
    282 uint32_t property_set(const std::string& name, const std::string& value) {
    283     if (name == "selinux.restorecon_recursive") {
    284         return PropertySetAsync(name, value, RestoreconRecursiveAsync);
    285     }
    286 
    287     return PropertySetImpl(name, value);
    288 }
    289 
    290 class SocketConnection {
    291  public:
    292   SocketConnection(int socket, const struct ucred& cred)
    293       : socket_(socket), cred_(cred) {}
    294 
    295   ~SocketConnection() {
    296     close(socket_);
    297   }
    298 
    299   bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
    300     return RecvFully(value, sizeof(*value), timeout_ms);
    301   }
    302 
    303   bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
    304     return RecvFully(chars, size, timeout_ms);
    305   }
    306 
    307   bool RecvString(std::string* value, uint32_t* timeout_ms) {
    308     uint32_t len = 0;
    309     if (!RecvUint32(&len, timeout_ms)) {
    310       return false;
    311     }
    312 
    313     if (len == 0) {
    314       *value = "";
    315       return true;
    316     }
    317 
    318     // http://b/35166374: don't allow init to make arbitrarily large allocations.
    319     if (len > 0xffff) {
    320       LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
    321       errno = ENOMEM;
    322       return false;
    323     }
    324 
    325     std::vector<char> chars(len);
    326     if (!RecvChars(&chars[0], len, timeout_ms)) {
    327       return false;
    328     }
    329 
    330     *value = std::string(&chars[0], len);
    331     return true;
    332   }
    333 
    334   bool SendUint32(uint32_t value) {
    335     int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
    336     return result == sizeof(value);
    337   }
    338 
    339   int socket() {
    340     return socket_;
    341   }
    342 
    343   const struct ucred& cred() {
    344     return cred_;
    345   }
    346 
    347  private:
    348   bool PollIn(uint32_t* timeout_ms) {
    349     struct pollfd ufds[1];
    350     ufds[0].fd = socket_;
    351     ufds[0].events = POLLIN;
    352     ufds[0].revents = 0;
    353     while (*timeout_ms > 0) {
    354       Timer timer;
    355       int nr = poll(ufds, 1, *timeout_ms);
    356       uint64_t millis = timer.duration().count();
    357       *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
    358 
    359       if (nr > 0) {
    360         return true;
    361       }
    362 
    363       if (nr == 0) {
    364         // Timeout
    365         break;
    366       }
    367 
    368       if (nr < 0 && errno != EINTR) {
    369         PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message";
    370         return false;
    371       } else { // errno == EINTR
    372         // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
    373         // to avoid slowing init down by causing EINTR with under millisecond timeout.
    374         if (*timeout_ms > 0) {
    375           --(*timeout_ms);
    376         }
    377       }
    378     }
    379 
    380     LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message.";
    381     return false;
    382   }
    383 
    384   bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
    385     size_t bytes_left = size;
    386     char* data = static_cast<char*>(data_ptr);
    387     while (*timeout_ms > 0 && bytes_left > 0) {
    388       if (!PollIn(timeout_ms)) {
    389         return false;
    390       }
    391 
    392       int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
    393       if (result <= 0) {
    394         return false;
    395       }
    396 
    397       bytes_left -= result;
    398       data += result;
    399     }
    400 
    401     return bytes_left == 0;
    402   }
    403 
    404   int socket_;
    405   struct ucred cred_;
    406 
    407   DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
    408 };
    409 
    410 static void handle_property_set(SocketConnection& socket,
    411                                 const std::string& name,
    412                                 const std::string& value,
    413                                 bool legacy_protocol) {
    414   const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
    415   if (!is_legal_property_name(name)) {
    416     LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
    417     socket.SendUint32(PROP_ERROR_INVALID_NAME);
    418     return;
    419   }
    420 
    421   struct ucred cr = socket.cred();
    422   char* source_ctx = nullptr;
    423   getpeercon(socket.socket(), &source_ctx);
    424 
    425   if (android::base::StartsWith(name, "ctl.")) {
    426     if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
    427       handle_control_message(name.c_str() + 4, value.c_str());
    428       if (!legacy_protocol) {
    429         socket.SendUint32(PROP_SUCCESS);
    430       }
    431     } else {
    432       LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
    433                  << " service ctl [" << value << "]"
    434                  << " uid:" << cr.uid
    435                  << " gid:" << cr.gid
    436                  << " pid:" << cr.pid;
    437       if (!legacy_protocol) {
    438         socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
    439       }
    440     }
    441   } else {
    442     if (check_mac_perms(name, source_ctx, &cr)) {
    443       uint32_t result = property_set(name, value);
    444       if (!legacy_protocol) {
    445         socket.SendUint32(result);
    446       }
    447     } else {
    448       LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
    449       if (!legacy_protocol) {
    450         socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
    451       }
    452     }
    453   }
    454 
    455   freecon(source_ctx);
    456 }
    457 
    458 static void handle_property_set_fd() {
    459     static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
    460 
    461     int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
    462     if (s == -1) {
    463         return;
    464     }
    465 
    466     struct ucred cr;
    467     socklen_t cr_size = sizeof(cr);
    468     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
    469         close(s);
    470         PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
    471         return;
    472     }
    473 
    474     SocketConnection socket(s, cr);
    475     uint32_t timeout_ms = kDefaultSocketTimeout;
    476 
    477     uint32_t cmd = 0;
    478     if (!socket.RecvUint32(&cmd, &timeout_ms)) {
    479         PLOG(ERROR) << "sys_prop: error while reading command from the socket";
    480         socket.SendUint32(PROP_ERROR_READ_CMD);
    481         return;
    482     }
    483 
    484     switch (cmd) {
    485     case PROP_MSG_SETPROP: {
    486         char prop_name[PROP_NAME_MAX];
    487         char prop_value[PROP_VALUE_MAX];
    488 
    489         if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
    490             !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
    491           PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
    492           return;
    493         }
    494 
    495         prop_name[PROP_NAME_MAX-1] = 0;
    496         prop_value[PROP_VALUE_MAX-1] = 0;
    497 
    498         handle_property_set(socket, prop_value, prop_value, true);
    499         break;
    500       }
    501 
    502     case PROP_MSG_SETPROP2: {
    503         std::string name;
    504         std::string value;
    505         if (!socket.RecvString(&name, &timeout_ms) ||
    506             !socket.RecvString(&value, &timeout_ms)) {
    507           PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
    508           socket.SendUint32(PROP_ERROR_READ_DATA);
    509           return;
    510         }
    511 
    512         handle_property_set(socket, name, value, false);
    513         break;
    514       }
    515 
    516     default:
    517         LOG(ERROR) << "sys_prop: invalid command " << cmd;
    518         socket.SendUint32(PROP_ERROR_INVALID_CMD);
    519         break;
    520     }
    521 }
    522 
    523 static bool load_properties_from_file(const char *, const char *);
    524 
    525 /*
    526  * Filter is used to decide which properties to load: NULL loads all keys,
    527  * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
    528  */
    529 static void load_properties(char *data, const char *filter)
    530 {
    531     char *key, *value, *eol, *sol, *tmp, *fn;
    532     size_t flen = 0;
    533 
    534     if (filter) {
    535         flen = strlen(filter);
    536     }
    537 
    538     sol = data;
    539     while ((eol = strchr(sol, '\n'))) {
    540         key = sol;
    541         *eol++ = 0;
    542         sol = eol;
    543 
    544         while (isspace(*key)) key++;
    545         if (*key == '#') continue;
    546 
    547         tmp = eol - 2;
    548         while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
    549 
    550         if (!strncmp(key, "import ", 7) && flen == 0) {
    551             fn = key + 7;
    552             while (isspace(*fn)) fn++;
    553 
    554             key = strchr(fn, ' ');
    555             if (key) {
    556                 *key++ = 0;
    557                 while (isspace(*key)) key++;
    558             }
    559 
    560             load_properties_from_file(fn, key);
    561 
    562         } else {
    563             value = strchr(key, '=');
    564             if (!value) continue;
    565             *value++ = 0;
    566 
    567             tmp = value - 2;
    568             while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
    569 
    570             while (isspace(*value)) value++;
    571 
    572             if (flen > 0) {
    573                 if (filter[flen - 1] == '*') {
    574                     if (strncmp(key, filter, flen - 1)) continue;
    575                 } else {
    576                     if (strcmp(key, filter)) continue;
    577                 }
    578             }
    579 
    580             property_set(key, value);
    581         }
    582     }
    583 }
    584 
    585 // Filter is used to decide which properties to load: NULL loads all keys,
    586 // "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
    587 static bool load_properties_from_file(const char* filename, const char* filter) {
    588     Timer t;
    589     std::string data;
    590     std::string err;
    591     if (!ReadFile(filename, &data, &err)) {
    592         PLOG(WARNING) << "Couldn't load property file: " << err;
    593         return false;
    594     }
    595     data.push_back('\n');
    596     load_properties(&data[0], filter);
    597     LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
    598     return true;
    599 }
    600 
    601 static void load_persistent_properties() {
    602     persistent_properties_loaded = 1;
    603 
    604     std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
    605     if (!dir) {
    606         PLOG(ERROR) << "Unable to open persistent property directory \""
    607                     << PERSISTENT_PROPERTY_DIR << "\"";
    608         return;
    609     }
    610 
    611     struct dirent* entry;
    612     while ((entry = readdir(dir.get())) != NULL) {
    613         if (strncmp("persist.", entry->d_name, strlen("persist."))) {
    614             continue;
    615         }
    616         if (entry->d_type != DT_REG) {
    617             continue;
    618         }
    619 
    620         // Open the file and read the property value.
    621         int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
    622         if (fd == -1) {
    623             PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\"";
    624             continue;
    625         }
    626 
    627         struct stat sb;
    628         if (fstat(fd, &sb) == -1) {
    629             PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed";
    630             close(fd);
    631             continue;
    632         }
    633 
    634         // File must not be accessible to others, be owned by root/root, and
    635         // not be a hard link to any other file.
    636         if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) {
    637             PLOG(ERROR) << "skipping insecure property file " << entry->d_name
    638                         << " (uid=" << sb.st_uid << " gid=" << sb.st_gid
    639                         << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")";
    640             close(fd);
    641             continue;
    642         }
    643 
    644         char value[PROP_VALUE_MAX];
    645         int length = read(fd, value, sizeof(value) - 1);
    646         if (length >= 0) {
    647             value[length] = 0;
    648             property_set(entry->d_name, value);
    649         } else {
    650             PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name;
    651         }
    652         close(fd);
    653     }
    654 }
    655 
    656 // persist.sys.usb.config values can't be combined on build-time when property
    657 // files are split into each partition.
    658 // So we need to apply the same rule of build/make/tools/post_process_props.py
    659 // on runtime.
    660 static void update_sys_usb_config() {
    661     bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
    662     std::string config = android::base::GetProperty("persist.sys.usb.config", "");
    663     if (config.empty()) {
    664         property_set("persist.sys.usb.config", is_debuggable ? "adb" : "none");
    665     } else if (is_debuggable && config.find("adb") == std::string::npos &&
    666                config.length() + 4 < PROP_VALUE_MAX) {
    667         config.append(",adb");
    668         property_set("persist.sys.usb.config", config);
    669     }
    670 }
    671 
    672 void property_load_boot_defaults() {
    673     if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
    674         // Try recovery path
    675         if (!load_properties_from_file("/prop.default", NULL)) {
    676             // Try legacy path
    677             load_properties_from_file("/default.prop", NULL);
    678         }
    679     }
    680     load_properties_from_file("/odm/default.prop", NULL);
    681     load_properties_from_file("/vendor/default.prop", NULL);
    682 
    683     update_sys_usb_config();
    684 }
    685 
    686 static void load_override_properties() {
    687     if (ALLOW_LOCAL_PROP_OVERRIDE) {
    688         load_properties_from_file("/data/local.prop", NULL);
    689     }
    690 }
    691 
    692 /* When booting an encrypted system, /data is not mounted when the
    693  * property service is started, so any properties stored there are
    694  * not loaded.  Vold triggers init to load these properties once it
    695  * has mounted /data.
    696  */
    697 void load_persist_props(void) {
    698     load_override_properties();
    699     /* Read persistent properties after all default values have been loaded. */
    700     load_persistent_properties();
    701     property_set("ro.persistent_properties.ready", "true");
    702 }
    703 
    704 void load_recovery_id_prop() {
    705     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
    706                                                                fs_mgr_free_fstab);
    707     if (!fstab) {
    708         PLOG(ERROR) << "unable to read default fstab";
    709         return;
    710     }
    711 
    712     fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), RECOVERY_MOUNT_POINT);
    713     if (rec == NULL) {
    714         LOG(ERROR) << "/recovery not specified in fstab";
    715         return;
    716     }
    717 
    718     int fd = open(rec->blk_device, O_RDONLY);
    719     if (fd == -1) {
    720         PLOG(ERROR) << "error opening block device " << rec->blk_device;
    721         return;
    722     }
    723 
    724     boot_img_hdr hdr;
    725     if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
    726         std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
    727         property_set("ro.recovery_id", hex);
    728     } else {
    729         PLOG(ERROR) << "error reading /recovery";
    730     }
    731 
    732     close(fd);
    733 }
    734 
    735 void load_system_props() {
    736     load_properties_from_file("/system/build.prop", NULL);
    737     load_properties_from_file("/odm/build.prop", NULL);
    738     load_properties_from_file("/vendor/build.prop", NULL);
    739     load_properties_from_file("/factory/factory.prop", "ro.*");
    740     load_recovery_id_prop();
    741 }
    742 
    743 void start_property_service() {
    744     property_set("ro.property_service.version", "2");
    745 
    746     property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
    747                                    false, 0666, 0, 0, nullptr, sehandle);
    748     if (property_set_fd == -1) {
    749         PLOG(ERROR) << "start_property_service socket creation failed";
    750         exit(1);
    751     }
    752 
    753     listen(property_set_fd, 8);
    754 
    755     register_epoll_handler(property_set_fd, handle_property_set_fd);
    756 }
    757 
    758 }  // namespace init
    759 }  // namespace android
    760