Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libsystemproperties
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_STATIC_LIBRARIES := libcxx
LOCAL_CFLAGS := -std=c++17 -Wno-unused-function
LOCAL_SRC_FILES := \
context_node.cpp \
contexts_serialized.cpp \
contexts_split.cpp \
prop_area.cpp \
prop_info.cpp \
system_properties.cpp \
system_property_api.cpp \
system_property_set.cpp \
property_info_parser.cpp

include $(BUILD_STATIC_LIBRARY)
4 changes: 1 addition & 3 deletions context_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
#include <limits.h>
#include <unistd.h>

#include <async_safe/log.h>

#include "system_properties/system_properties.h"

// pthread_mutex_lock() calls into system_properties in the case of contention.
Expand All @@ -53,7 +51,7 @@ bool ContextNode::Open(bool access_rw, bool* fsetxattr_failed) {
if (access_rw) {
pa_ = prop_area::map_prop_area_rw(filename.c_str(), context_, fsetxattr_failed);
} else {
pa_ = prop_area::map_prop_area(filename.c_str());
pa_ = prop_area::map_prop_area(filename.c_str(), nullptr);
}
lock_.unlock();
return pa_;
Expand Down
43 changes: 39 additions & 4 deletions contexts_serialized.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,14 @@

#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <new>

#include <async_safe/log.h>
#include <private/android_filesystem_config.h>

#include "system_properties/system_properties.h"

bool ContextsSerialized::InitializeContextNodes() {
Expand Down Expand Up @@ -71,7 +69,7 @@ bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_f
serial_prop_area_ = prop_area::map_prop_area_rw(
serial_filename_.c_str(), "u:object_r:properties_serial:s0", fsetxattr_failed);
} else {
serial_prop_area_ = prop_area::map_prop_area(serial_filename_.c_str());
serial_prop_area_ = prop_area::map_prop_area(serial_filename_.c_str(), &rw_);
}
return serial_prop_area_;
}
Expand Down Expand Up @@ -148,6 +146,12 @@ prop_area* ContextsSerialized::GetPropAreaForName(const char* name) {
return context_node->pa();
}

const char* ContextsSerialized::GetContextForName(const char* name) {
const char* context;
property_info_area_file_->GetPropertyInfo(name, &context, nullptr);
return context;
}

void ContextsSerialized::ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
for (size_t i = 0; i < num_context_nodes_; ++i) {
if (context_nodes_[i].CheckAccessAndOpen()) {
Expand All @@ -156,6 +160,37 @@ void ContextsSerialized::ForEach(void (*propfn)(const prop_info* pi, void* cooki
}
}

bool ContextsSerialized::Compact() {
for (size_t i = 0; i < num_context_nodes_; ++i) {
if (!context_nodes_[i].CheckAccessAndOpen() || !context_nodes_[i].pa()->compact()) {
return false;
}
}
return !serial_prop_area_ || serial_prop_area_->compact();
}

bool ContextsSerialized::CompactContext(const char* context, bool* found) {
bool ret = true;
*found = false;

for (size_t i = 0; i < num_context_nodes_; ++i) {
if (!strcmp(context_nodes_[i].context(), context)) {
*found = true;
if (!context_nodes_[i].CheckAccessAndOpen() || !context_nodes_[i].pa()->compact()) {
ret = false;
}
}
}

if (!*found && serial_prop_area_ &&
!strcmp(context, "u:object_r:properties_serial:s0")) {
*found = true;
ret = serial_prop_area_->compact();
}

return *found && ret;
}

void ContextsSerialized::ResetAccess() {
for (size_t i = 0; i < num_context_nodes_; ++i) {
context_nodes_[i].ResetAccess();
Expand Down
46 changes: 43 additions & 3 deletions contexts_split.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
#include <string.h>
#include <sys/stat.h>

#include <async_safe/log.h>

#include "system_properties/context_node.h"
#include "system_properties/system_properties.h"

Expand Down Expand Up @@ -197,7 +195,7 @@ bool ContextsSplit::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed
serial_prop_area_ = prop_area::map_prop_area_rw(
filename.c_str(), "u:object_r:properties_serial:s0", fsetxattr_failed);
} else {
serial_prop_area_ = prop_area::map_prop_area(filename.c_str());
serial_prop_area_ = prop_area::map_prop_area(filename.c_str(), &rw_);
}
return serial_prop_area_;
}
Expand Down Expand Up @@ -268,13 +266,19 @@ bool ContextsSplit::InitializeProperties() {
// still need the system / platform properties to function.
if (access("/vendor/etc/selinux/vendor_property_contexts", R_OK) != -1) {
InitializePropertiesFromFile("/vendor/etc/selinux/vendor_property_contexts");
} else {
// Fallback to nonplat_* if vendor_* doesn't exist.
InitializePropertiesFromFile("/vendor/etc/selinux/nonplat_property_contexts");
}
} else {
if (!InitializePropertiesFromFile("/plat_property_contexts")) {
return false;
}
if (access("/vendor_property_contexts", R_OK) != -1) {
InitializePropertiesFromFile("/vendor_property_contexts");
} else {
// Fallback to nonplat_* if vendor_* doesn't exist.
InitializePropertiesFromFile("/nonplat_property_contexts");
}
}

Expand Down Expand Up @@ -336,6 +340,14 @@ prop_area* ContextsSplit::GetPropAreaForName(const char* name) {
return cnode->pa();
}

const char* ContextsSplit::GetContextForName(const char* name) {
auto entry = GetPrefixNodeForName(name);
if (!entry) {
return nullptr;
}
return entry->context->context();
}

void ContextsSplit::ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
ListForEach(contexts_, [propfn, cookie](ContextListNode* l) {
if (l->CheckAccessAndOpen()) {
Expand All @@ -344,6 +356,34 @@ void ContextsSplit::ForEach(void (*propfn)(const prop_info* pi, void* cookie), v
});
}

bool ContextsSplit::Compact() {
bool ret = true;
ListForEach(contexts_, [&ret](ContextListNode* l) {
ret = ret && l->CheckAccessAndOpen() && l->pa()->compact();
});
return ret && (!serial_prop_area_ || serial_prop_area_->compact());
}

bool ContextsSplit::CompactContext(const char* context, bool* found) {
bool ret = true;
*found = false;

ListForEach(contexts_, [&ret, found, context](ContextListNode* l) {
if (!strcmp(l->context(), context)) {
*found = true;
ret = ret && l->CheckAccessAndOpen() && l->pa()->compact();
}
});

if (!*found && serial_prop_area_ &&
!strcmp(context, "u:object_r:properties_serial:s0")) {
*found = true;
ret = serial_prop_area_->compact();
}

return *found && ret;
}

void ContextsSplit::ResetAccess() {
ListForEach(contexts_, [](ContextListNode* l) { l->ResetAccess(); });
}
Expand Down
32 changes: 32 additions & 0 deletions include/api/hacks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#undef __INTRODUCED_IN
#define __INTRODUCED_IN(...)

#undef __BIONIC_AVAILABILITY_GUARD
#define __BIONIC_AVAILABILITY_GUARD(...) 1

// <async_safe/CHECK.h>
#define CHECK(x) /* NOP */

// <async_safe/log.h>
#define async_safe_format_buffer snprintf
#define async_safe_format_log(...) /* NOP */

// Rename symbols
#pragma redefine_extname __system_property_set __system_property_set2
#pragma redefine_extname __system_property_find __system_property_find2
#pragma redefine_extname __system_property_read_callback __system_property_read_callback2
#pragma redefine_extname __system_property_foreach __system_property_foreach2
#pragma redefine_extname __system_property_wait __system_property_wait2
#pragma redefine_extname __system_property_read __system_property_read2
#pragma redefine_extname __system_property_get __system_property_get2
#pragma redefine_extname __system_property_find_nth __system_property_find_nth2
#pragma redefine_extname __system_property_set_filename __system_property_set_filename2
#pragma redefine_extname __system_property_area_init __system_property_area_init2
#pragma redefine_extname __system_property_area_serial __system_property_area_serial2
#pragma redefine_extname __system_property_add __system_property_add2
#pragma redefine_extname __system_property_update __system_property_update2
#pragma redefine_extname __system_property_serial __system_property_serial2
#pragma redefine_extname __system_properties_init __system_properties_init2
#pragma redefine_extname __system_property_wait_any __system_property_wait_any2
37 changes: 30 additions & 7 deletions include/api/system_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#include <stddef.h>
#include <stdint.h>

#include "hacks.h"

__BEGIN_DECLS

/** An opaque structure representing a system property. */
Expand Down Expand Up @@ -229,6 +231,34 @@ int __system_property_add(const char* _Nonnull __name, unsigned int __name_lengt
*/
int __system_property_update(prop_info* _Nonnull __pi, const char* _Nonnull __value, unsigned int __value_length);

/**
* Delete a system property.
*
* Returns 0 on success, -1 if the property area is full.
*/
int __system_property_delete(const char* _Nonnull __name, bool __prune);

/**
* Compact the property area to preserve dictionary tree structure after deletions.
*
* Returns 0 on success, -1 on failure.
*/
bool __system_property_compact(void);

/**
* Compact the property area for a specific context label.
*
* Returns true on success, false on failure or if the context was not found.
*/
bool __system_property_compact_context(const char* _Nonnull __context);

/**
* Get context of a property.
*
* Returns the context on success, nullptr if fail.
*/
const char* _Nullable __system_property_get_context(const char* _Nonnull __name);

/**
* Reloads the system properties from disk.
* Not intended for use by any apps except the Zygote.
Expand All @@ -247,11 +277,4 @@ int __system_properties_zygote_reload(void) __INTRODUCED_IN(35);
#endif /* __BIONIC_AVAILABILITY_GUARD(35) */


/**
* Deprecated: previously for testing, but now that SystemProperties is its own
* testable class, there is never a reason to call this function and its
* implementation simply returns -1.
*/
int __system_property_set_filename(const char* _Nullable __unused __filename);

__END_DECLS
4 changes: 4 additions & 0 deletions include/system_properties/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ class Contexts {
bool load_default_path = false) = 0;
virtual prop_area* GetPropAreaForName(const char* name) = 0;
virtual prop_area* GetSerialPropArea() = 0;
virtual const char* GetContextForName(const char* name) = 0;
virtual void ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) = 0;
virtual bool Compact() = 0;
virtual bool CompactContext(const char* context, bool* found) = 0;
virtual void ResetAccess() = 0;
virtual void FreeAndUnmap() = 0;
bool rw_ = false;
};
21 changes: 20 additions & 1 deletion include/system_properties/contexts_pre_split.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#pragma once

#include <string.h>

#include "contexts.h"
#include "prop_area.h"
#include "prop_info.h"
Expand All @@ -39,7 +41,7 @@ class ContextsPreSplit : public Contexts {

// We'll never initialize this legacy option as writable, so don't even check the arg.
virtual bool Initialize(bool, const char* filename, bool*, bool) override {
pre_split_prop_area_ = prop_area::map_prop_area(filename);
pre_split_prop_area_ = prop_area::map_prop_area(filename, &rw_);
return pre_split_prop_area_ != nullptr;
}

Expand All @@ -51,10 +53,27 @@ class ContextsPreSplit : public Contexts {
return pre_split_prop_area_;
}

virtual const char* GetContextForName(const char*) override {
return "u:object_r:properties_device:s0";
}

virtual void ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) override {
pre_split_prop_area_->foreach (propfn, cookie);
}

virtual bool Compact() override {
return pre_split_prop_area_->compact();
}

virtual bool CompactContext(const char* context, bool* found) override {
if (context && !strcmp(context, GetContextForName(""))) {
*found = true;
return pre_split_prop_area_->compact();
}
*found = false;
return false;
}

// This is a no-op for pre-split properties as there is only one property file and it is
// accessible by all domains
virtual void ResetAccess() override {
Expand Down
3 changes: 3 additions & 0 deletions include/system_properties/contexts_serialized.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ class ContextsSerialized : public Contexts {
virtual prop_area* GetSerialPropArea() override {
return serial_prop_area_;
}
virtual const char* GetContextForName(const char* name) override;
virtual void ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) override;
virtual bool Compact() override;
virtual bool CompactContext(const char* context, bool* found) override;
virtual void ResetAccess() override;
virtual void FreeAndUnmap() override;

Expand Down
3 changes: 3 additions & 0 deletions include/system_properties/contexts_split.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ class ContextsSplit : public Contexts {
virtual prop_area* GetSerialPropArea() override {
return serial_prop_area_;
}
virtual const char* GetContextForName(const char* name) override;
virtual void ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) override;
virtual bool Compact() override;
virtual bool CompactContext(const char* context, bool* found) override;
virtual void ResetAccess() override;
virtual void FreeAndUnmap() override;

Expand Down
Loading