Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2016 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 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
     18 
     19 #include "android-base/properties.h"
     20 
     21 #include <sys/system_properties.h>
     22 #include <sys/_system_properties.h>
     23 
     24 #include <algorithm>
     25 #include <chrono>
     26 #include <string>
     27 
     28 #include <android-base/parseint.h>
     29 
     30 using namespace std::chrono_literals;
     31 
     32 namespace android {
     33 namespace base {
     34 
     35 std::string GetProperty(const std::string& key, const std::string& default_value) {
     36   const prop_info* pi = __system_property_find(key.c_str());
     37   if (pi == nullptr) return default_value;
     38 
     39   char buf[PROP_VALUE_MAX];
     40   if (__system_property_read(pi, nullptr, buf) > 0) return buf;
     41 
     42   // If the property exists but is empty, also return the default value.
     43   // Since we can't remove system properties, "empty" is traditionally
     44   // the same as "missing" (this was true for cutils' property_get).
     45   return default_value;
     46 }
     47 
     48 bool GetBoolProperty(const std::string& key, bool default_value) {
     49   std::string value = GetProperty(key, "");
     50   if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
     51     return true;
     52   } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
     53     return false;
     54   }
     55   return default_value;
     56 }
     57 
     58 template <typename T>
     59 T GetIntProperty(const std::string& key, T default_value, T min, T max) {
     60   T result;
     61   std::string value = GetProperty(key, "");
     62   if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
     63   return default_value;
     64 }
     65 
     66 template <typename T>
     67 T GetUintProperty(const std::string& key, T default_value, T max) {
     68   T result;
     69   std::string value = GetProperty(key, "");
     70   if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
     71   return default_value;
     72 }
     73 
     74 template int8_t GetIntProperty(const std::string&, int8_t, int8_t, int8_t);
     75 template int16_t GetIntProperty(const std::string&, int16_t, int16_t, int16_t);
     76 template int32_t GetIntProperty(const std::string&, int32_t, int32_t, int32_t);
     77 template int64_t GetIntProperty(const std::string&, int64_t, int64_t, int64_t);
     78 
     79 template uint8_t GetUintProperty(const std::string&, uint8_t, uint8_t);
     80 template uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t);
     81 template uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t);
     82 template uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t);
     83 
     84 bool SetProperty(const std::string& key, const std::string& value) {
     85   return (__system_property_set(key.c_str(), value.c_str()) == 0);
     86 }
     87 
     88 struct WaitForPropertyData {
     89   bool done;
     90   const std::string* expected_value;
     91   unsigned last_read_serial;
     92 };
     93 
     94 static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
     95   WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
     96   if (*data->expected_value == value) {
     97     data->done = true;
     98   } else {
     99     data->last_read_serial = serial;
    100   }
    101 }
    102 
    103 // TODO: chrono_utils?
    104 static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
    105   auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
    106   auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
    107   ts.tv_sec = s.count();
    108   ts.tv_nsec = ns.count();
    109 }
    110 
    111 // TODO: boot_clock?
    112 using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
    113 
    114 static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout,
    115                            const AbsTime& start_time) {
    116   auto now = std::chrono::steady_clock::now();
    117   auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
    118   if (time_elapsed >= relative_timeout) {
    119     ts = { 0, 0 };
    120   } else {
    121     auto remaining_timeout = relative_timeout - time_elapsed;
    122     DurationToTimeSpec(ts, remaining_timeout);
    123   }
    124 }
    125 
    126 // Waits for the system property `key` to be created.
    127 // Times out after `relative_timeout`.
    128 // Sets absolute_timeout which represents absolute time for the timeout.
    129 // Returns nullptr on timeout.
    130 static const prop_info* WaitForPropertyCreation(const std::string& key,
    131                                                 const std::chrono::milliseconds& relative_timeout,
    132                                                 const AbsTime& start_time) {
    133   // Find the property's prop_info*.
    134   const prop_info* pi;
    135   unsigned global_serial = 0;
    136   while ((pi = __system_property_find(key.c_str())) == nullptr) {
    137     // The property doesn't even exist yet.
    138     // Wait for a global change and then look again.
    139     timespec ts;
    140     UpdateTimeSpec(ts, relative_timeout, start_time);
    141     if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
    142   }
    143   return pi;
    144 }
    145 
    146 bool WaitForProperty(const std::string& key, const std::string& expected_value,
    147                      std::chrono::milliseconds relative_timeout) {
    148   auto start_time = std::chrono::steady_clock::now();
    149   const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time);
    150   if (pi == nullptr) return false;
    151 
    152   WaitForPropertyData data;
    153   data.expected_value = &expected_value;
    154   data.done = false;
    155   while (true) {
    156     timespec ts;
    157     // Check whether the property has the value we're looking for?
    158     __system_property_read_callback(pi, WaitForPropertyCallback, &data);
    159     if (data.done) return true;
    160 
    161     // It didn't, so wait for the property to change before checking again.
    162     UpdateTimeSpec(ts, relative_timeout, start_time);
    163     uint32_t unused;
    164     if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
    165   }
    166 }
    167 
    168 bool WaitForPropertyCreation(const std::string& key,
    169                              std::chrono::milliseconds relative_timeout) {
    170   auto start_time = std::chrono::steady_clock::now();
    171   return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
    172 }
    173 
    174 }  // namespace base
    175 }  // namespace android
    176