11e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes/*
21e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * Copyright (C) 2016 The Android Open Source Project
31e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes *
41e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
51e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * you may not use this file except in compliance with the License.
61e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * You may obtain a copy of the License at
71e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes *
81e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
91e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes *
101e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * Unless required by applicable law or agreed to in writing, software
111e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
121e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * See the License for the specific language governing permissions and
141e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes * limitations under the License.
151e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes */
161e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
17b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
18b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes
191e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes#include "android-base/properties.h"
201e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
211e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes#include <sys/system_properties.h>
22b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes#include <sys/_system_properties.h>
231e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
2403edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes#include <algorithm>
2503edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes#include <chrono>
261e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes#include <string>
271e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
281e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes#include <android-base/parseint.h>
291e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
3003edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughesusing namespace std::chrono_literals;
3103edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes
321e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughesnamespace android {
331e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughesnamespace base {
341e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
351e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughesstd::string GetProperty(const std::string& key, const std::string& default_value) {
361e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  const prop_info* pi = __system_property_find(key.c_str());
371e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  if (pi == nullptr) return default_value;
381e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
391e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  char buf[PROP_VALUE_MAX];
401e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  if (__system_property_read(pi, nullptr, buf) > 0) return buf;
411e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
421e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  // If the property exists but is empty, also return the default value.
431e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  // Since we can't remove system properties, "empty" is traditionally
441e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  // the same as "missing" (this was true for cutils' property_get).
451e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  return default_value;
461e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}
471e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
481e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughesbool GetBoolProperty(const std::string& key, bool default_value) {
491e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  std::string value = GetProperty(key, "");
501e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
511e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes    return true;
521e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
531e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes    return false;
541e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  }
551e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  return default_value;
561e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}
571e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
581e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate <typename T>
591e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott HughesT GetIntProperty(const std::string& key, T default_value, T min, T max) {
601e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  T result;
611e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  std::string value = GetProperty(key, "");
62da46b392f10d2809b5696632f67485f272ec5698Elliott Hughes  if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
631e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  return default_value;
641e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}
651e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
661e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate <typename T>
671e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott HughesT GetUintProperty(const std::string& key, T default_value, T max) {
681e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  T result;
691e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  std::string value = GetProperty(key, "");
70da46b392f10d2809b5696632f67485f272ec5698Elliott Hughes  if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
711e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  return default_value;
721e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}
731e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
741e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate int8_t GetIntProperty(const std::string&, int8_t, int8_t, int8_t);
751e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate int16_t GetIntProperty(const std::string&, int16_t, int16_t, int16_t);
761e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate int32_t GetIntProperty(const std::string&, int32_t, int32_t, int32_t);
771e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate int64_t GetIntProperty(const std::string&, int64_t, int64_t, int64_t);
781e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
791e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate uint8_t GetUintProperty(const std::string&, uint8_t, uint8_t);
801e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t);
811e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t);
821e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughestemplate uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t);
831e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
841e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughesbool SetProperty(const std::string& key, const std::string& value) {
851e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes  return (__system_property_set(key.c_str(), value.c_str()) == 0);
861e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}
871e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes
88b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughesstruct WaitForPropertyData {
89b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  bool done;
90b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  const std::string* expected_value;
91b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  unsigned last_read_serial;
92b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes};
93b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes
94b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughesstatic void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
95b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
96b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  if (*data->expected_value == value) {
97b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes    data->done = true;
98b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  } else {
99b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes    data->last_read_serial = serial;
100b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  }
101b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes}
102b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes
10303edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes// TODO: chrono_utils?
10403edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughesstatic void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
10503edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
10603edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
10703edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  ts.tv_sec = s.count();
10803edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  ts.tv_nsec = ns.count();
10903edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes}
11003edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes
111e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Parkusing AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
112e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park
11303edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughesstatic void UpdateTimeSpec(timespec& ts,
114e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park                           const AbsTime& timeout) {
11503edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  auto now = std::chrono::steady_clock::now();
11603edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
11703edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  if (remaining_timeout < 0ns) {
11803edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    ts = { 0, 0 };
11903edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  } else {
12003edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    DurationToTimeSpec(ts, remaining_timeout);
12103edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  }
12203edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes}
12303edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes
124e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park// Waits for the system property `key` to be created.
125e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park// Times out after `relative_timeout`.
126e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park// Sets absolute_timeout which represents absolute time for the timeout.
127e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park// Returns nullptr on timeout.
128e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Parkstatic const prop_info* WaitForPropertyCreation(const std::string& key,
129e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park                                                const std::chrono::milliseconds& relative_timeout,
130e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park                                                AbsTime& absolute_timeout) {
13103edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  // TODO: boot_clock?
13203edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes  auto now = std::chrono::steady_clock::now();
133e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  absolute_timeout = now + relative_timeout;
13403edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes
135b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  // Find the property's prop_info*.
136b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  const prop_info* pi;
137b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  unsigned global_serial = 0;
138b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  while ((pi = __system_property_find(key.c_str())) == nullptr) {
139b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes    // The property doesn't even exist yet.
140b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes    // Wait for a global change and then look again.
141e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park    timespec ts;
14203edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    UpdateTimeSpec(ts, absolute_timeout);
143e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park    if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
144b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  }
145e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  return pi;
146e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park}
147e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park
148e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Parkbool WaitForProperty(const std::string& key,
149e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park                     const std::string& expected_value,
150e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park                     std::chrono::milliseconds relative_timeout) {
151e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  AbsTime absolute_timeout;
152e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
153e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  if (pi == nullptr) return false;
154b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes
155b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  WaitForPropertyData data;
156b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  data.expected_value = &expected_value;
157b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  data.done = false;
158b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  while (true) {
159e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park    timespec ts;
160b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes    // Check whether the property has the value we're looking for?
161b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes    __system_property_read_callback(pi, WaitForPropertyCallback, &data);
16203edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    if (data.done) return true;
163b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes
16403edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    // It didn't, so wait for the property to change before checking again.
16503edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    UpdateTimeSpec(ts, absolute_timeout);
16603edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    uint32_t unused;
16703edc9f7647b3ac9db8a4743acc98b0238b846fbElliott Hughes    if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
168b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes  }
169b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes}
170b30769a87acc15fc7f628d8541cdf97aba22e2e2Elliott Hughes
171e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Parkbool WaitForPropertyCreation(const std::string& key,
172e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park                             std::chrono::milliseconds relative_timeout) {
173e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  AbsTime absolute_timeout;
174e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park  return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
175e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park}
176e2d986daa644672dabe5f594701028dc04fcc5ceKeun-young Park
1771e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}  // namespace base
1781e88c8c0ac31a4b07da4228ed9ac41e50ae56886Elliott Hughes}  // namespace android
179