Home | History | Annotate | Download | only in system_properties
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include "system_properties/system_properties.h"
     30 
     31 #include <errno.h>
     32 #include <stdatomic.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <sys/stat.h>
     36 #include <sys/types.h>
     37 #include <unistd.h>
     38 
     39 #include <new>
     40 
     41 #include <async_safe/log.h>
     42 
     43 #include "private/ErrnoRestorer.h"
     44 #include "private/bionic_futex.h"
     45 
     46 #include "system_properties/context_node.h"
     47 #include "system_properties/prop_area.h"
     48 #include "system_properties/prop_info.h"
     49 
     50 #define SERIAL_DIRTY(serial) ((serial)&1)
     51 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
     52 
     53 static bool is_dir(const char* pathname) {
     54   struct stat info;
     55   if (stat(pathname, &info) == -1) {
     56     return false;
     57   }
     58   return S_ISDIR(info.st_mode);
     59 }
     60 
     61 bool SystemProperties::Init(const char* filename) {
     62   // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
     63   ErrnoRestorer errno_restorer;
     64 
     65   if (initialized_) {
     66     contexts_->ResetAccess();
     67     return true;
     68   }
     69 
     70   if (strlen(filename) > PROP_FILENAME_MAX) {
     71     return false;
     72   }
     73   strcpy(property_filename_, filename);
     74 
     75   if (is_dir(property_filename_)) {
     76     if (access("/dev/__properties__/property_info", R_OK) == 0) {
     77       contexts_ = new (contexts_data_) ContextsSerialized();
     78       if (!contexts_->Initialize(false, property_filename_, nullptr)) {
     79         return false;
     80       }
     81     } else {
     82       contexts_ = new (contexts_data_) ContextsSplit();
     83       if (!contexts_->Initialize(false, property_filename_, nullptr)) {
     84         return false;
     85       }
     86     }
     87   } else {
     88     contexts_ = new (contexts_data_) ContextsPreSplit();
     89     if (!contexts_->Initialize(false, property_filename_, nullptr)) {
     90       return false;
     91     }
     92   }
     93   initialized_ = true;
     94   return true;
     95 }
     96 
     97 bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
     98   if (strlen(filename) > PROP_FILENAME_MAX) {
     99     return false;
    100   }
    101   strcpy(property_filename_, filename);
    102 
    103   contexts_ = new (contexts_data_) ContextsSerialized();
    104   if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
    105     return false;
    106   }
    107   initialized_ = true;
    108   return true;
    109 }
    110 
    111 uint32_t SystemProperties::AreaSerial() {
    112   if (!initialized_) {
    113     return -1;
    114   }
    115 
    116   prop_area* pa = contexts_->GetSerialPropArea();
    117   if (!pa) {
    118     return -1;
    119   }
    120 
    121   // Make sure this read fulfilled before __system_property_serial
    122   return atomic_load_explicit(pa->serial(), memory_order_acquire);
    123 }
    124 
    125 const prop_info* SystemProperties::Find(const char* name) {
    126   if (!initialized_) {
    127     return nullptr;
    128   }
    129 
    130   prop_area* pa = contexts_->GetPropAreaForName(name);
    131   if (!pa) {
    132     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
    133     return nullptr;
    134   }
    135 
    136   return pa->find(name);
    137 }
    138 
    139 static bool is_read_only(const char* name) {
    140   return strncmp(name, "ro.", 3) == 0;
    141 }
    142 
    143 int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
    144   while (true) {
    145     uint32_t serial = Serial(pi);  // acquire semantics
    146     size_t len = SERIAL_VALUE_LEN(serial);
    147     memcpy(value, pi->value, len + 1);
    148     // TODO: Fix the synchronization scheme here.
    149     // There is no fully supported way to implement this kind
    150     // of synchronization in C++11, since the memcpy races with
    151     // updates to pi, and the data being accessed is not atomic.
    152     // The following fence is unintuitive, but would be the
    153     // correct one if memcpy used memory_order_relaxed atomic accesses.
    154     // In practice it seems unlikely that the generated code would
    155     // would be any different, so this should be OK.
    156     atomic_thread_fence(memory_order_acquire);
    157     if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
    158       if (name != nullptr) {
    159         size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
    160         if (namelen >= PROP_NAME_MAX) {
    161           async_safe_format_log(ANDROID_LOG_ERROR, "libc",
    162                                 "The property name length for \"%s\" is >= %d;"
    163                                 " please use __system_property_read_callback"
    164                                 " to read this property. (the name is truncated to \"%s\")",
    165                                 pi->name, PROP_NAME_MAX - 1, name);
    166         }
    167       }
    168       if (is_read_only(pi->name) && pi->is_long()) {
    169         async_safe_format_log(
    170             ANDROID_LOG_ERROR, "libc",
    171             "The property \"%s\" has a value with length %zu that is too large for"
    172             " __system_property_get()/__system_property_read(); use"
    173             " __system_property_read_callback() instead.",
    174             pi->name, strlen(pi->long_value()));
    175       }
    176       return len;
    177     }
    178   }
    179 }
    180 
    181 void SystemProperties::ReadCallback(const prop_info* pi,
    182                                     void (*callback)(void* cookie, const char* name,
    183                                                      const char* value, uint32_t serial),
    184                                     void* cookie) {
    185   // Read only properties don't need to copy the value to a temporary buffer, since it can never
    186   // change.
    187   if (is_read_only(pi->name)) {
    188     uint32_t serial = Serial(pi);
    189     if (pi->is_long()) {
    190       callback(cookie, pi->name, pi->long_value(), serial);
    191     } else {
    192       callback(cookie, pi->name, pi->value, serial);
    193     }
    194     return;
    195   }
    196 
    197   while (true) {
    198     uint32_t serial = Serial(pi);  // acquire semantics
    199     size_t len = SERIAL_VALUE_LEN(serial);
    200     char value_buf[len + 1];
    201 
    202     memcpy(value_buf, pi->value, len);
    203     value_buf[len] = '\0';
    204 
    205     // TODO: see todo in Read function
    206     atomic_thread_fence(memory_order_acquire);
    207     if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
    208       callback(cookie, pi->name, value_buf, serial);
    209       return;
    210     }
    211   }
    212 }
    213 
    214 int SystemProperties::Get(const char* name, char* value) {
    215   const prop_info* pi = Find(name);
    216 
    217   if (pi != 0) {
    218     return Read(pi, nullptr, value);
    219   } else {
    220     value[0] = 0;
    221     return 0;
    222   }
    223 }
    224 
    225 int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
    226   if (len >= PROP_VALUE_MAX) {
    227     return -1;
    228   }
    229 
    230   if (!initialized_) {
    231     return -1;
    232   }
    233 
    234   prop_area* pa = contexts_->GetSerialPropArea();
    235   if (!pa) {
    236     return -1;
    237   }
    238 
    239   uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
    240   serial |= 1;
    241   atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
    242   // The memcpy call here also races.  Again pretend it
    243   // used memory_order_relaxed atomics, and use the analogous
    244   // counterintuitive fence.
    245   atomic_thread_fence(memory_order_release);
    246   strlcpy(pi->value, value, len + 1);
    247 
    248   atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_release);
    249   __futex_wake(&pi->serial, INT32_MAX);
    250 
    251   atomic_store_explicit(pa->serial(), atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
    252                         memory_order_release);
    253   __futex_wake(pa->serial(), INT32_MAX);
    254 
    255   return 0;
    256 }
    257 
    258 int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
    259                           unsigned int valuelen) {
    260   if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
    261     return -1;
    262   }
    263 
    264   if (namelen < 1) {
    265     return -1;
    266   }
    267 
    268   if (!initialized_) {
    269     return -1;
    270   }
    271 
    272   prop_area* serial_pa = contexts_->GetSerialPropArea();
    273   if (serial_pa == nullptr) {
    274     return -1;
    275   }
    276 
    277   prop_area* pa = contexts_->GetPropAreaForName(name);
    278   if (!pa) {
    279     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
    280     return -1;
    281   }
    282 
    283   bool ret = pa->add(name, namelen, value, valuelen);
    284   if (!ret) {
    285     return -1;
    286   }
    287 
    288   // There is only a single mutator, but we want to make sure that
    289   // updates are visible to a reader waiting for the update.
    290   atomic_store_explicit(serial_pa->serial(),
    291                         atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
    292                         memory_order_release);
    293   __futex_wake(serial_pa->serial(), INT32_MAX);
    294   return 0;
    295 }
    296 
    297 // Wait for non-locked serial, and retrieve it with acquire semantics.
    298 uint32_t SystemProperties::Serial(const prop_info* pi) {
    299   uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
    300   while (SERIAL_DIRTY(serial)) {
    301     __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr);
    302     serial = load_const_atomic(&pi->serial, memory_order_acquire);
    303   }
    304   return serial;
    305 }
    306 
    307 uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
    308   uint32_t new_serial;
    309   Wait(nullptr, old_serial, &new_serial, nullptr);
    310   return new_serial;
    311 }
    312 
    313 bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
    314                             const timespec* relative_timeout) {
    315   // Are we waiting on the global serial or a specific serial?
    316   atomic_uint_least32_t* serial_ptr;
    317   if (pi == nullptr) {
    318     if (!initialized_) {
    319       return -1;
    320     }
    321 
    322     prop_area* serial_pa = contexts_->GetSerialPropArea();
    323     if (serial_pa == nullptr) {
    324       return -1;
    325     }
    326 
    327     serial_ptr = serial_pa->serial();
    328   } else {
    329     serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
    330   }
    331 
    332   uint32_t new_serial;
    333   do {
    334     int rc;
    335     if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
    336       return false;
    337     }
    338     new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
    339   } while (new_serial == old_serial);
    340 
    341   *new_serial_ptr = new_serial;
    342   return true;
    343 }
    344 
    345 const prop_info* SystemProperties::FindNth(unsigned n) {
    346   struct find_nth {
    347     const uint32_t sought;
    348     uint32_t current;
    349     const prop_info* result;
    350 
    351     explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
    352     }
    353     static void fn(const prop_info* pi, void* ptr) {
    354       find_nth* self = reinterpret_cast<find_nth*>(ptr);
    355       if (self->current++ == self->sought) self->result = pi;
    356     }
    357   } state(n);
    358   Foreach(find_nth::fn, &state);
    359   return state.result;
    360 }
    361 
    362 int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
    363   if (!initialized_) {
    364     return -1;
    365   }
    366 
    367   contexts_->ForEach(propfn, cookie);
    368 
    369   return 0;
    370 }
    371