Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
7a002567
Commit
7a002567
authored
Sep 06, 2018
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use libsystemproperties in resetprop
Upstream to latest Android Pie
parent
ad7ec799
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
3404 additions
and
2216 deletions
+3404
-2216
build.gradle
build.gradle
+1
-1
gradle.properties
gradle.properties
+0
-3
Android.mk
native/jni/Android.mk
+8
-4
Application.mk
native/jni/Application.mk
+2
-1
utils.h
native/jni/include/utils.h
+8
-4
Android.mk
native/jni/resetprop/libsystemproperties/Android.mk
+15
-0
context_node.cpp
native/jni/resetprop/libsystemproperties/context_node.cpp
+98
-0
contexts_serialized.cpp
...jni/resetprop/libsystemproperties/contexts_serialized.cpp
+172
-0
contexts_split.cpp
native/jni/resetprop/libsystemproperties/contexts_split.cpp
+363
-0
log.h
...ni/resetprop/libsystemproperties/include/async_safe/log.h
+4
-0
hacks.h
native/jni/resetprop/libsystemproperties/include/hacks.h
+14
-0
ErrnoRestorer.h
...tprop/libsystemproperties/include/private/ErrnoRestorer.h
+43
-0
bionic_futex.h
...etprop/libsystemproperties/include/private/bionic_futex.h
+17
-14
bionic_lock.h
...setprop/libsystemproperties/include/private/bionic_lock.h
+19
-4
bionic_macros.h
...tprop/libsystemproperties/include/private/bionic_macros.h
+105
-0
property_info_parser.h
...rties/include/property_info_parser/property_info_parser.h
+224
-0
context_node.h
...systemproperties/include/system_properties/context_node.h
+67
-0
contexts.h
.../libsystemproperties/include/system_properties/contexts.h
+45
-0
contexts_pre_split.h
...properties/include/system_properties/contexts_pre_split.h
+69
-0
contexts_serialized.h
...roperties/include/system_properties/contexts_serialized.h
+61
-0
contexts_split.h
...stemproperties/include/system_properties/contexts_split.h
+59
-0
prop_area.h
...libsystemproperties/include/system_properties/prop_area.h
+162
-0
prop_info.h
...libsystemproperties/include/system_properties/prop_info.h
+90
-0
system_properties.h
...mproperties/include/system_properties/system_properties.h
+89
-0
prop_area.cpp
native/jni/resetprop/libsystemproperties/prop_area.cpp
+373
-0
prop_info.cpp
native/jni/resetprop/libsystemproperties/prop_info.cpp
+55
-0
property_info_parser.cpp
...ni/resetprop/libsystemproperties/property_info_parser.cpp
+246
-0
system_properties.cpp
...e/jni/resetprop/libsystemproperties/system_properties.cpp
+370
-0
persist_properties.c
native/jni/resetprop/persist_properties.c
+0
-0
_system_properties.h
native/jni/resetprop/private/_system_properties.h
+11
-16
bionic_defs.h
native/jni/resetprop/private/bionic_defs.h
+39
-0
bionic_macros.h
native/jni/resetprop/private/bionic_macros.h
+39
-3
futex.h
native/jni/resetprop/private/futex.h
+0
-77
redefs.h
native/jni/resetprop/private/redefs.h
+1
-0
stdatomic.h
native/jni/resetprop/private/stdatomic.h
+0
-370
system_properties.h
native/jni/resetprop/private/system_properties.h
+13
-15
xattr.h
native/jni/resetprop/private/xattr.h
+0
-61
system_properties.cpp
native/jni/resetprop/system_properties.cpp
+0
-1569
system_property_api.cpp
native/jni/resetprop/system_property_api.cpp
+126
-0
system_property_set.cpp
native/jni/resetprop/system_property_set.cpp
+317
-0
misc.c
native/jni/utils/misc.c
+79
-74
No files found.
build.gradle
View file @
7a002567
...
@@ -7,7 +7,7 @@ buildscript {
...
@@ -7,7 +7,7 @@ buildscript {
jcenter
()
jcenter
()
}
}
dependencies
{
dependencies
{
classpath
'com.android.tools.build:gradle:3.
1.4
'
classpath
'com.android.tools.build:gradle:3.
2.0-rc02
'
// NOTE: Do not place your application dependencies here; they belong
// NOTE: Do not place your application dependencies here; they belong
...
...
gradle.properties
View file @
7a002567
...
@@ -20,6 +20,3 @@ org.gradle.parallel=true
...
@@ -20,6 +20,3 @@ org.gradle.parallel=true
# When set to true the Gradle daemon is used to run the build. For local developer builds this is our favorite property.
# When set to true the Gradle daemon is used to run the build. For local developer builds this is our favorite property.
# The developer environment is optimized for speed and feedback so we nearly always run Gradle jobs with the daemon.
# The developer environment is optimized for speed and feedback so we nearly always run Gradle jobs with the daemon.
org.gradle.daemon
=
true
org.gradle.daemon
=
true
# Configuration on demand is not supported by the current version of the Android Gradle plugin since you are using Gradle version 4.6 or above
org.gradle.configureondemand
=
false
native/jni/Android.mk
View file @
7a002567
...
@@ -10,6 +10,7 @@ LIBLZ4 := $(EXT_PATH)/lz4/lib
...
@@ -10,6 +10,7 @@ LIBLZ4 := $(EXT_PATH)/lz4/lib
LIBBZ2 := $(EXT_PATH)/bzip2
LIBBZ2 := $(EXT_PATH)/bzip2
LIBFDT := $(EXT_PATH)/dtc/libfdt
LIBFDT := $(EXT_PATH)/dtc/libfdt
LIBNANOPB := $(EXT_PATH)/nanopb
LIBNANOPB := $(EXT_PATH)/nanopb
LIBSYSTEMPROPERTIES := jni/resetprop/libsystemproperties/include
COMMON_UTILS := \
COMMON_UTILS := \
utils/file.c \
utils/file.c \
utils/list.c \
utils/list.c \
...
@@ -27,13 +28,14 @@ ifdef B_MAGISK
...
@@ -27,13 +28,14 @@ ifdef B_MAGISK
include $(CLEAR_VARS)
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_MODULE := magisk
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_STATIC_LIBRARIES := libnanopb
LOCAL_STATIC_LIBRARIES := libnanopb
libsystemproperties
LOCAL_C_INCLUDES := \
LOCAL_C_INCLUDES := \
jni/include \
jni/include \
jni/magiskpolicy \
jni/magiskpolicy \
$(EXT_PATH)/include \
$(EXT_PATH)/include \
$(LIBSELINUX) \
$(LIBSELINUX) \
$(LIBNANOPB)
$(LIBNANOPB) \
$(LIBSYSTEMPROPERTIES)
LOCAL_SRC_FILES := \
LOCAL_SRC_FILES := \
core/magisk.c \
core/magisk.c \
...
@@ -45,9 +47,10 @@ LOCAL_SRC_FILES := \
...
@@ -45,9 +47,10 @@ LOCAL_SRC_FILES := \
magiskhide/magiskhide.c \
magiskhide/magiskhide.c \
magiskhide/proc_monitor.c \
magiskhide/proc_monitor.c \
magiskhide/hide_utils.c \
magiskhide/hide_utils.c \
resetprop/persist_props.c \
resetprop/persist_prop
ertie
s.c \
resetprop/resetprop.c \
resetprop/resetprop.c \
resetprop/system_properties.cpp \
resetprop/system_property_api.cpp \
resetprop/system_property_set.cpp \
su/su.c \
su/su.c \
su/activity.c \
su/activity.c \
su/pts.c \
su/pts.c \
...
@@ -145,3 +148,4 @@ endif
...
@@ -145,3 +148,4 @@ endif
# Externals
# Externals
########################
########################
include jni/external/Android.mk
include jni/external/Android.mk
include jni/resetprop/libsystemproperties/Android.mk
native/jni/Application.mk
View file @
7a002567
APP_ABI := armeabi-v7a x86
APP_ABI := armeabi-v7a x86
APP_CFLAGS := -std=gnu99 ${MAGISK_DEBUG} \
APP_CFLAGS := -std=gnu99 ${MAGISK_DEBUG} \
-DMAGISK_VERSION="${MAGISK_VERSION}" -DMAGISK_VER_CODE=${MAGISK_VER_CODE}
-DMAGISK_VERSION="${MAGISK_VERSION}" -DMAGISK_VER_CODE=${MAGISK_VER_CODE}
APP_CPPFLAGS := -std=c++11
APP_CPPFLAGS := -std=c++14
APP_STL := system
APP_PLATFORM := android-16
APP_PLATFORM := android-16
APP_CFLAGS += -Wno-implicit-function-declaration
APP_CFLAGS += -Wno-implicit-function-declaration
...
...
native/jni/include/utils.h
View file @
7a002567
...
@@ -82,8 +82,6 @@ pid_t xfork();
...
@@ -82,8 +82,6 @@ pid_t xfork();
// misc.c
// misc.c
#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 })
#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 })
#define getline my_getline
#define getdelim my_getdelim
unsigned
get_shell_uid
();
unsigned
get_shell_uid
();
unsigned
get_system_uid
();
unsigned
get_system_uid
();
...
@@ -92,8 +90,6 @@ int check_data();
...
@@ -92,8 +90,6 @@ int check_data();
int
file_to_vector
(
const
char
*
filename
,
struct
vector
*
v
);
int
file_to_vector
(
const
char
*
filename
,
struct
vector
*
v
);
int
vector_to_file
(
const
char
*
filename
,
struct
vector
*
v
);
int
vector_to_file
(
const
char
*
filename
,
struct
vector
*
v
);
ssize_t
fdgets
(
char
*
buf
,
size_t
size
,
int
fd
);
ssize_t
fdgets
(
char
*
buf
,
size_t
size
,
int
fd
);
ssize_t
my_getline
(
char
**
lineptr
,
size_t
*
n
,
FILE
*
stream
);
ssize_t
my_getdelim
(
char
**
lineptr
,
size_t
*
n
,
int
delim
,
FILE
*
stream
);
void
ps
(
void
(
*
func
)(
int
));
void
ps
(
void
(
*
func
)(
int
));
int
check_proc_name
(
int
pid
,
const
char
*
filter
);
int
check_proc_name
(
int
pid
,
const
char
*
filter
);
void
unlock_blocks
();
void
unlock_blocks
();
...
@@ -109,6 +105,14 @@ void wait_till_exists(const char *target);
...
@@ -109,6 +105,14 @@ void wait_till_exists(const char *target);
void
gen_rand_str
(
char
*
buf
,
int
len
);
void
gen_rand_str
(
char
*
buf
,
int
len
);
int
strend
(
const
char
*
s1
,
const
char
*
s2
);
int
strend
(
const
char
*
s1
,
const
char
*
s2
);
#define getline __getline
#define getdelim __getdelim
#define fsetxattr __fsetxattr
ssize_t
__getline
(
char
**
lineptr
,
size_t
*
n
,
FILE
*
stream
);
ssize_t
__getdelim
(
char
**
lineptr
,
size_t
*
n
,
int
delim
,
FILE
*
stream
);
int
__fsetxattr
(
int
fd
,
const
char
*
name
,
const
void
*
value
,
size_t
size
,
int
flags
);
// file.c
// file.c
#define align(p, a) (((p) + (a) - 1) / (a) * (a))
#define align(p, a) (((p) + (a) - 1) / (a) * (a))
...
...
native/jni/resetprop/libsystemproperties/Android.mk
0 → 100644
View file @
7a002567
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= libsystemproperties
LOCAL_C_INCLUDES := $(LIBSYSTEMPROPERTIES)
LOCAL_SRC_FILES := \
context_node.cpp \
contexts_serialized.cpp \
contexts_split.cpp \
prop_area.cpp \
prop_info.cpp \
system_properties.cpp \
property_info_parser.cpp
include $(BUILD_STATIC_LIBRARY)
native/jni/resetprop/libsystemproperties/context_node.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "system_properties/context_node.h"
#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.
// This creates a risk of dead lock if any system_properties functions
// use pthread locks after system_property initialization.
//
// For this reason, the below three functions use a bionic Lock and static
// allocation of memory for each filename.
bool
ContextNode
::
Open
(
bool
access_rw
,
bool
*
fsetxattr_failed
)
{
lock_
.
lock
();
if
(
pa_
)
{
lock_
.
unlock
();
return
true
;
}
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
filename_
,
context_
);
if
(
len
<
0
||
len
>=
PROP_FILENAME_MAX
)
{
lock_
.
unlock
();
return
false
;
}
if
(
access_rw
)
{
pa_
=
prop_area
::
map_prop_area_rw
(
filename
,
context_
,
fsetxattr_failed
);
}
else
{
pa_
=
prop_area
::
map_prop_area
(
filename
);
}
lock_
.
unlock
();
return
pa_
;
}
bool
ContextNode
::
CheckAccessAndOpen
()
{
if
(
!
pa_
&&
!
no_access_
)
{
if
(
!
CheckAccess
()
||
!
Open
(
false
,
nullptr
))
{
no_access_
=
true
;
}
}
return
pa_
;
}
void
ContextNode
::
ResetAccess
()
{
if
(
!
CheckAccess
())
{
Unmap
();
no_access_
=
true
;
}
else
{
no_access_
=
false
;
}
}
bool
ContextNode
::
CheckAccess
()
{
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
filename_
,
context_
);
if
(
len
<
0
||
len
>=
PROP_FILENAME_MAX
)
{
return
false
;
}
return
access
(
filename
,
R_OK
)
==
0
;
}
void
ContextNode
::
Unmap
()
{
prop_area
::
unmap_prop_area
(
&
pa_
);
}
native/jni/resetprop/libsystemproperties/contexts_serialized.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "system_properties/contexts_serialized.h"
#include <fcntl.h>
#include <limits.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 "system_properties/system_properties.h"
bool
ContextsSerialized
::
InitializeContextNodes
()
{
auto
num_context_nodes
=
property_info_area_file_
->
num_contexts
();
auto
context_nodes_mmap_size
=
sizeof
(
ContextNode
)
*
num_context_nodes
;
// We want to avoid malloc in system properties, so we take an anonymous map instead (b/31659220).
void
*
const
map_result
=
mmap
(
nullptr
,
context_nodes_mmap_size
,
PROT_READ
|
PROT_WRITE
,
MAP_PRIVATE
|
MAP_ANONYMOUS
,
-
1
,
0
);
if
(
map_result
==
MAP_FAILED
)
{
return
false
;
}
prctl
(
PR_SET_VMA
,
PR_SET_VMA_ANON_NAME
,
map_result
,
context_nodes_mmap_size
,
"System property context nodes"
);
context_nodes_
=
reinterpret_cast
<
ContextNode
*>
(
map_result
);
num_context_nodes_
=
num_context_nodes
;
context_nodes_mmap_size_
=
context_nodes_mmap_size
;
for
(
size_t
i
=
0
;
i
<
num_context_nodes
;
++
i
)
{
new
(
&
context_nodes_
[
i
])
ContextNode
(
property_info_area_file_
->
context
(
i
),
filename_
);
}
return
true
;
}
bool
ContextsSerialized
::
MapSerialPropertyArea
(
bool
access_rw
,
bool
*
fsetxattr_failed
)
{
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/properties_serial"
,
filename_
);
if
(
len
<
0
||
len
>=
PROP_FILENAME_MAX
)
{
serial_prop_area_
=
nullptr
;
return
false
;
}
if
(
access_rw
)
{
serial_prop_area_
=
prop_area
::
map_prop_area_rw
(
filename
,
"u:object_r:properties_serial:s0"
,
fsetxattr_failed
);
}
else
{
serial_prop_area_
=
prop_area
::
map_prop_area
(
filename
);
}
return
serial_prop_area_
;
}
bool
ContextsSerialized
::
InitializeProperties
()
{
if
(
!
property_info_area_file_
.
LoadDefaultPath
())
{
return
false
;
}
if
(
!
InitializeContextNodes
())
{
FreeAndUnmap
();
return
false
;
}
return
true
;
}
bool
ContextsSerialized
::
Initialize
(
bool
writable
,
const
char
*
filename
,
bool
*
fsetxattr_failed
)
{
filename_
=
filename
;
if
(
!
InitializeProperties
())
{
return
false
;
}
if
(
writable
)
{
mkdir
(
filename_
,
S_IRWXU
|
S_IXGRP
|
S_IXOTH
);
bool
open_failed
=
false
;
if
(
fsetxattr_failed
)
{
*
fsetxattr_failed
=
false
;
}
for
(
size_t
i
=
0
;
i
<
num_context_nodes_
;
++
i
)
{
if
(
!
context_nodes_
[
i
].
Open
(
true
,
fsetxattr_failed
))
{
open_failed
=
true
;
}
}
if
(
open_failed
||
!
MapSerialPropertyArea
(
true
,
fsetxattr_failed
))
{
FreeAndUnmap
();
return
false
;
}
}
else
{
if
(
!
MapSerialPropertyArea
(
false
,
nullptr
))
{
FreeAndUnmap
();
return
false
;
}
}
return
true
;
}
prop_area
*
ContextsSerialized
::
GetPropAreaForName
(
const
char
*
name
)
{
uint32_t
index
;
property_info_area_file_
->
GetPropertyInfoIndexes
(
name
,
&
index
,
nullptr
);
if
(
index
==
~
0u
||
index
>=
num_context_nodes_
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"Could not find context for property
\"
%s
\"
"
,
name
);
return
nullptr
;
}
auto
*
context_node
=
&
context_nodes_
[
index
];
if
(
!
context_node
->
pa
())
{
// We explicitly do not check no_access_ in this case because unlike the
// case of foreach(), we want to generate an selinux audit for each
// non-permitted property access in this function.
context_node
->
Open
(
false
,
nullptr
);
}
return
context_node
->
pa
();
}
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
())
{
context_nodes_
[
i
].
pa
()
->
foreach
(
propfn
,
cookie
);
}
}
}
void
ContextsSerialized
::
ResetAccess
()
{
for
(
size_t
i
=
0
;
i
<
num_context_nodes_
;
++
i
)
{
context_nodes_
[
i
].
ResetAccess
();
}
}
void
ContextsSerialized
::
FreeAndUnmap
()
{
property_info_area_file_
.
Reset
();
if
(
context_nodes_
!=
nullptr
)
{
for
(
size_t
i
=
0
;
i
<
num_context_nodes_
;
++
i
)
{
context_nodes_
[
i
].
Unmap
();
}
munmap
(
context_nodes_
,
context_nodes_mmap_size_
);
context_nodes_
=
nullptr
;
}
prop_area
::
unmap_prop_area
(
&
serial_prop_area_
);
serial_prop_area_
=
nullptr
;
}
native/jni/resetprop/libsystemproperties/contexts_split.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "system_properties/contexts_split.h"
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <async_safe/log.h>
#include "system_properties/context_node.h"
#include "system_properties/system_properties.h"
class
ContextListNode
:
public
ContextNode
{
public
:
ContextListNode
(
ContextListNode
*
next
,
const
char
*
context
,
const
char
*
filename
)
:
ContextNode
(
strdup
(
context
),
filename
),
next
(
next
)
{
}
~
ContextListNode
()
{
free
(
const_cast
<
char
*>
(
context
()));
}
ContextListNode
*
next
;
};
struct
PrefixNode
{
PrefixNode
(
struct
PrefixNode
*
next
,
const
char
*
prefix
,
ContextListNode
*
context
)
:
prefix
(
strdup
(
prefix
)),
prefix_len
(
strlen
(
prefix
)),
context
(
context
),
next
(
next
)
{
}
~
PrefixNode
()
{
free
(
prefix
);
}
char
*
prefix
;
const
size_t
prefix_len
;
ContextListNode
*
context
;
PrefixNode
*
next
;
};
template
<
typename
List
,
typename
...
Args
>
static
inline
void
ListAdd
(
List
**
list
,
Args
...
args
)
{
*
list
=
new
List
(
*
list
,
args
...);
}
static
void
ListAddAfterLen
(
PrefixNode
**
list
,
const
char
*
prefix
,
ContextListNode
*
context
)
{
size_t
prefix_len
=
strlen
(
prefix
);
auto
next_list
=
list
;
while
(
*
next_list
)
{
if
((
*
next_list
)
->
prefix_len
<
prefix_len
||
(
*
next_list
)
->
prefix
[
0
]
==
'*'
)
{
ListAdd
(
next_list
,
prefix
,
context
);
return
;
}
next_list
=
&
(
*
next_list
)
->
next
;
}
ListAdd
(
next_list
,
prefix
,
context
);
}
template
<
typename
List
,
typename
Func
>
static
void
ListForEach
(
List
*
list
,
Func
func
)
{
while
(
list
)
{
func
(
list
);
list
=
list
->
next
;
}
}
template
<
typename
List
,
typename
Func
>
static
List
*
ListFind
(
List
*
list
,
Func
func
)
{
while
(
list
)
{
if
(
func
(
list
))
{
return
list
;
}
list
=
list
->
next
;
}
return
nullptr
;
}
template
<
typename
List
>
static
void
ListFree
(
List
**
list
)
{
while
(
*
list
)
{
auto
old_list
=
*
list
;
*
list
=
old_list
->
next
;
delete
old_list
;
}
}
// The below two functions are duplicated from label_support.c in libselinux.
// TODO: Find a location suitable for these functions such that both libc and
// libselinux can share a common source file.
// The read_spec_entries and read_spec_entry functions may be used to
// replace sscanf to read entries from spec files. The file and
// property services now use these.
// Read an entry from a spec file (e.g. file_contexts)
static
inline
int
read_spec_entry
(
char
**
entry
,
char
**
ptr
,
int
*
len
)
{
*
entry
=
nullptr
;
char
*
tmp_buf
=
nullptr
;
while
(
isspace
(
**
ptr
)
&&
**
ptr
!=
'\0'
)
(
*
ptr
)
++
;
tmp_buf
=
*
ptr
;
*
len
=
0
;
while
(
!
isspace
(
**
ptr
)
&&
**
ptr
!=
'\0'
)
{
(
*
ptr
)
++
;
(
*
len
)
++
;
}
if
(
*
len
)
{
*
entry
=
strndup
(
tmp_buf
,
*
len
);
if
(
!*
entry
)
return
-
1
;
}
return
0
;
}
// line_buf - Buffer containing the spec entries .
// num_args - The number of spec parameter entries to process.
// ... - A 'char **spec_entry' for each parameter.
// returns - The number of items processed.
//
// This function calls read_spec_entry() to do the actual string processing.
static
int
read_spec_entries
(
char
*
line_buf
,
int
num_args
,
...)
{
char
**
spec_entry
,
*
buf_p
;
int
len
,
rc
,
items
,
entry_len
=
0
;
va_list
ap
;
len
=
strlen
(
line_buf
);
if
(
line_buf
[
len
-
1
]
==
'\n'
)
line_buf
[
len
-
1
]
=
'\0'
;
else
// Handle case if line not \n terminated by bumping
// the len for the check below (as the line is NUL
// terminated by getline(3))
len
++
;
buf_p
=
line_buf
;
while
(
isspace
(
*
buf_p
))
buf_p
++
;
// Skip comment lines and empty lines.
if
(
*
buf_p
==
'#'
||
*
buf_p
==
'\0'
)
return
0
;
// Process the spec file entries
va_start
(
ap
,
num_args
);
items
=
0
;
while
(
items
<
num_args
)
{
spec_entry
=
va_arg
(
ap
,
char
**
);
if
(
len
-
1
==
buf_p
-
line_buf
)
{
va_end
(
ap
);
return
items
;
}
rc
=
read_spec_entry
(
spec_entry
,
&
buf_p
,
&
entry_len
);
if
(
rc
<
0
)
{
va_end
(
ap
);
return
rc
;
}
if
(
entry_len
)
items
++
;
}
va_end
(
ap
);
return
items
;
}
bool
ContextsSplit
::
MapSerialPropertyArea
(
bool
access_rw
,
bool
*
fsetxattr_failed
)
{
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/properties_serial"
,
filename_
);
if
(
len
<
0
||
len
>=
PROP_FILENAME_MAX
)
{
serial_prop_area_
=
nullptr
;
return
false
;
}
if
(
access_rw
)
{
serial_prop_area_
=
prop_area
::
map_prop_area_rw
(
filename
,
"u:object_r:properties_serial:s0"
,
fsetxattr_failed
);
}
else
{
serial_prop_area_
=
prop_area
::
map_prop_area
(
filename
);
}
return
serial_prop_area_
;
}
bool
ContextsSplit
::
InitializePropertiesFromFile
(
const
char
*
filename
)
{
FILE
*
file
=
fopen
(
filename
,
"re"
);
if
(
!
file
)
{
return
false
;
}
char
*
buffer
=
nullptr
;
size_t
line_len
;
char
*
prop_prefix
=
nullptr
;
char
*
context
=
nullptr
;
while
(
getline
(
&
buffer
,
&
line_len
,
file
)
>
0
)
{
int
items
=
read_spec_entries
(
buffer
,
2
,
&
prop_prefix
,
&
context
);
if
(
items
<=
0
)
{
continue
;
}
if
(
items
==
1
)
{
free
(
prop_prefix
);
continue
;
}
// init uses ctl.* properties as an IPC mechanism and does not write them
// to a property file, therefore we do not need to create property files
// to store them.
if
(
!
strncmp
(
prop_prefix
,
"ctl."
,
4
))
{
free
(
prop_prefix
);
free
(
context
);
continue
;
}
auto
old_context
=
ListFind
(
contexts_
,
[
context
](
ContextListNode
*
l
)
{
return
!
strcmp
(
l
->
context
(),
context
);
});
if
(
old_context
)
{
ListAddAfterLen
(
&
prefixes_
,
prop_prefix
,
old_context
);
}
else
{
ListAdd
(
&
contexts_
,
context
,
filename_
);
ListAddAfterLen
(
&
prefixes_
,
prop_prefix
,
contexts_
);
}
free
(
prop_prefix
);
free
(
context
);
}
free
(
buffer
);
fclose
(
file
);
return
true
;
}
bool
ContextsSplit
::
InitializeProperties
()
{
// If we do find /property_contexts, then this is being
// run as part of the OTA updater on older release that had
// /property_contexts - b/34370523
if
(
InitializePropertiesFromFile
(
"/property_contexts"
))
{
return
true
;
}
// Use property_contexts from /system & /vendor, fall back to those from /
if
(
access
(
"/system/etc/selinux/plat_property_contexts"
,
R_OK
)
!=
-
1
)
{
if
(
!
InitializePropertiesFromFile
(
"/system/etc/selinux/plat_property_contexts"
))
{
return
false
;
}
// Don't check for failure here, so we always have a sane list of properties.
// E.g. In case of recovery, the vendor partition will not have mounted and we
// 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"
);
}
}
return
true
;
}
bool
ContextsSplit
::
Initialize
(
bool
writable
,
const
char
*
filename
,
bool
*
fsetxattr_failed
)
{
filename_
=
filename
;
if
(
!
InitializeProperties
())
{
return
false
;
}
if
(
writable
)
{
mkdir
(
filename_
,
S_IRWXU
|
S_IXGRP
|
S_IXOTH
);
bool
open_failed
=
false
;
if
(
fsetxattr_failed
)
{
*
fsetxattr_failed
=
false
;
}
ListForEach
(
contexts_
,
[
&
fsetxattr_failed
,
&
open_failed
](
ContextListNode
*
l
)
{
if
(
!
l
->
Open
(
true
,
fsetxattr_failed
))
{
open_failed
=
true
;
}
});
if
(
open_failed
||
!
MapSerialPropertyArea
(
true
,
fsetxattr_failed
))
{
FreeAndUnmap
();
return
false
;
}
}
else
{
if
(
!
MapSerialPropertyArea
(
false
,
nullptr
))
{
FreeAndUnmap
();
return
false
;
}
}
return
true
;
}
prop_area
*
ContextsSplit
::
GetPropAreaForName
(
const
char
*
name
)
{
auto
entry
=
ListFind
(
prefixes_
,
[
name
](
PrefixNode
*
l
)
{
return
l
->
prefix
[
0
]
==
'*'
||
!
strncmp
(
l
->
prefix
,
name
,
l
->
prefix_len
);
});
if
(
!
entry
)
{
return
nullptr
;
}
auto
cnode
=
entry
->
context
;
if
(
!
cnode
->
pa
())
{
// We explicitly do not check no_access_ in this case because unlike the
// case of foreach(), we want to generate an selinux audit for each
// non-permitted property access in this function.
cnode
->
Open
(
false
,
nullptr
);
}
return
cnode
->
pa
();
}
void
ContextsSplit
::
ForEach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
ListForEach
(
contexts_
,
[
propfn
,
cookie
](
ContextListNode
*
l
)
{
if
(
l
->
CheckAccessAndOpen
())
{
l
->
pa
()
->
foreach
(
propfn
,
cookie
);
}
});
}
void
ContextsSplit
::
ResetAccess
()
{
ListForEach
(
contexts_
,
[](
ContextListNode
*
l
)
{
l
->
ResetAccess
();
});
}
void
ContextsSplit
::
FreeAndUnmap
()
{
ListFree
(
&
prefixes_
);
ListFree
(
&
contexts_
);
prop_area
::
unmap_prop_area
(
&
serial_prop_area_
);
}
native/jni/resetprop/libsystemproperties/include/async_safe/log.h
0 → 100644
View file @
7a002567
#pragma once
#define async_safe_format_buffer snprintf
#define async_safe_format_log(...)
/* NOP */
native/jni/resetprop/libsystemproperties/include/hacks.h
0 → 100644
View file @
7a002567
#pragma once
#include <stdio.h>
#ifndef PR_SET_VMA
#define PR_SET_VMA 0x53564d41
#endif
#ifndef PR_SET_VMA_ANON_NAME
#define PR_SET_VMA_ANON_NAME 0
#endif
#define getline __getline
#define fsetxattr __fsetxattr
extern
"C"
ssize_t
__getline
(
char
**
,
size_t
*
,
FILE
*
);
extern
"C"
int
__fsetxattr
(
int
,
const
char
*
,
const
void
*
,
size_t
,
int
);
native/jni/resetprop/libsystemproperties/include/private/ErrnoRestorer.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ERRNO_RESTORER_H
#define ERRNO_RESTORER_H
#include <errno.h>
#include "bionic_macros.h"
class
ErrnoRestorer
{
public
:
explicit
ErrnoRestorer
()
:
saved_errno_
(
errno
)
{
}
~
ErrnoRestorer
()
{
errno
=
saved_errno_
;
}
void
override
(
int
new_errno
)
{
saved_errno_
=
new_errno
;
}
private
:
int
saved_errno_
;
DISALLOW_COPY_AND_ASSIGN
(
ErrnoRestorer
);
};
#endif // ERRNO_RESTORER_H
native/jni/resetprop/private/bionic_futex.h
→
native/jni/resetprop/
libsystemproperties/include/
private/bionic_futex.h
View file @
7a002567
...
@@ -29,20 +29,17 @@
...
@@ -29,20 +29,17 @@
#define _BIONIC_FUTEX_H
#define _BIONIC_FUTEX_H
#include <errno.h>
#include <errno.h>
#include
"futex.h"
#include
<linux/futex.h>
#include <stdbool.h>
#include <stdbool.h>
#include <stddef.h>
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/cdefs.h>
#include <sys/syscall.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <unistd.h>
__BEGIN_DECLS
struct
timespec
;
struct
timespec
;
static
inline
int
__futex
(
volatile
void
*
ftx
,
int
op
,
int
value
,
static
inline
__always_inline
int
__futex
(
volatile
void
*
ftx
,
int
op
,
int
value
,
const
struct
timespec
*
timeout
,
const
timespec
*
timeout
,
int
bitset
)
{
int
bitset
)
{
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
int
saved_errno
=
errno
;
int
saved_errno
=
errno
;
int
result
=
syscall
(
__NR_futex
,
ftx
,
op
,
value
,
timeout
,
NULL
,
bitset
);
int
result
=
syscall
(
__NR_futex
,
ftx
,
op
,
value
,
timeout
,
NULL
,
bitset
);
...
@@ -54,24 +51,30 @@ static inline int __futex(volatile void* ftx, int op, int value,
...
@@ -54,24 +51,30 @@ static inline int __futex(volatile void* ftx, int op, int value,
}
}
static
inline
int
__futex_wake
(
volatile
void
*
ftx
,
int
count
)
{
static
inline
int
__futex_wake
(
volatile
void
*
ftx
,
int
count
)
{
return
__futex
(
ftx
,
FUTEX_WAKE
,
count
,
NULL
,
0
);
return
__futex
(
ftx
,
FUTEX_WAKE
,
count
,
nullptr
,
0
);
}
}
static
inline
int
__futex_wake_ex
(
volatile
void
*
ftx
,
bool
shared
,
int
count
)
{
static
inline
int
__futex_wake_ex
(
volatile
void
*
ftx
,
bool
shared
,
int
count
)
{
return
__futex
(
ftx
,
shared
?
FUTEX_WAKE
:
FUTEX_WAKE_PRIVATE
,
count
,
NULL
,
0
);
return
__futex
(
ftx
,
shared
?
FUTEX_WAKE
:
FUTEX_WAKE_PRIVATE
,
count
,
nullptr
,
0
);
}
}
static
inline
int
__futex_wait
(
volatile
void
*
ftx
,
int
value
,
const
struct
timespec
*
timeout
)
{
static
inline
int
__futex_wait
(
volatile
void
*
ftx
,
int
value
,
const
timespec
*
timeout
)
{
return
__futex
(
ftx
,
FUTEX_WAIT
,
value
,
timeout
,
0
);
return
__futex
(
ftx
,
FUTEX_WAIT
,
value
,
timeout
,
0
);
}
}
static
inline
int
__futex_wait_ex
(
volatile
void
*
ftx
,
bool
shared
,
int
value
,
static
inline
int
__futex_wait_ex
(
volatile
void
*
ftx
,
bool
shared
,
int
value
)
{
bool
use_realtime_clock
,
const
struct
timespec
*
abs_timeout
)
{
return
__futex
(
ftx
,
(
shared
?
FUTEX_WAIT_BITSET
:
FUTEX_WAIT_BITSET_PRIVATE
),
value
,
nullptr
,
return
__futex
(
ftx
,
(
shared
?
FUTEX_WAIT_BITSET
:
FUTEX_WAIT_BITSET_PRIVATE
)
|
(
use_realtime_clock
?
FUTEX_CLOCK_REALTIME
:
0
),
value
,
abs_timeout
,
FUTEX_BITSET_MATCH_ANY
);
FUTEX_BITSET_MATCH_ANY
);
}
}
__END_DECLS
__LIBC_HIDDEN__
int
__futex_wait_ex
(
volatile
void
*
ftx
,
bool
shared
,
int
value
,
bool
use_realtime_clock
,
const
timespec
*
abs_timeout
);
static
inline
int
__futex_pi_unlock
(
volatile
void
*
ftx
,
bool
shared
)
{
return
__futex
(
ftx
,
shared
?
FUTEX_UNLOCK_PI
:
FUTEX_UNLOCK_PI_PRIVATE
,
0
,
nullptr
,
0
);
}
__LIBC_HIDDEN__
int
__futex_pi_lock_ex
(
volatile
void
*
ftx
,
bool
shared
,
bool
use_realtime_clock
,
const
timespec
*
abs_timeout
);
#endif
/* _BIONIC_FUTEX_H */
#endif
/* _BIONIC_FUTEX_H */
native/jni/resetprop/private/bionic_lock.h
→
native/jni/resetprop/
libsystemproperties/include/
private/bionic_lock.h
View file @
7a002567
...
@@ -28,9 +28,9 @@
...
@@ -28,9 +28,9 @@
#ifndef _BIONIC_LOCK_H
#ifndef _BIONIC_LOCK_H
#define _BIONIC_LOCK_H
#define _BIONIC_LOCK_H
#include
"stdatomic.h"
#include
<stdatomic.h>
#include "bionic_futex.h"
#include "
private/
bionic_futex.h"
#include "bionic_macros.h"
#include "
private/
bionic_macros.h"
// Lock is used in places like pthread_rwlock_t, which can be initialized without calling
// Lock is used in places like pthread_rwlock_t, which can be initialized without calling
// an initialization function. So make sure Lock can be initialized by setting its memory to 0.
// an initialization function. So make sure Lock can be initialized by setting its memory to 0.
...
@@ -64,7 +64,7 @@ class Lock {
...
@@ -64,7 +64,7 @@ class Lock {
}
}
while
(
atomic_exchange_explicit
(
&
state
,
LockedWithWaiter
,
memory_order_acquire
)
!=
Unlocked
)
{
while
(
atomic_exchange_explicit
(
&
state
,
LockedWithWaiter
,
memory_order_acquire
)
!=
Unlocked
)
{
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
__futex_wait_ex
(
&
state
,
process_shared
,
LockedWithWaiter
,
false
,
nullptr
);
__futex_wait_ex
(
&
state
,
process_shared
,
LockedWithWaiter
);
}
}
return
;
return
;
}
}
...
@@ -76,4 +76,19 @@ class Lock {
...
@@ -76,4 +76,19 @@ class Lock {
}
}
};
};
class
LockGuard
{
public
:
LockGuard
(
Lock
&
lock
)
:
lock_
(
lock
)
{
lock_
.
lock
();
}
~
LockGuard
()
{
lock_
.
unlock
();
}
DISALLOW_COPY_AND_ASSIGN
(
LockGuard
);
private
:
Lock
&
lock_
;
};
#endif // _BIONIC_LOCK_H
#endif // _BIONIC_LOCK_H
native/jni/resetprop/libsystemproperties/include/private/bionic_macros.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _BIONIC_MACROS_H_
#define _BIONIC_MACROS_H_
#include <stdint.h>
// Frameworks OpenGL code currently leaks this header and allows
// collisions with other declarations, e.g., from libnativehelper.
// TODO: Remove once cleaned up. b/18334516
#if !defined(DISALLOW_COPY_AND_ASSIGN)
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
// It goes in the private: declarations in a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#endif // !defined(DISALLOW_COPY_AND_ASSIGN)
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
((sizeof(value) == 8) \
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
static
constexpr
uintptr_t
align_down
(
uintptr_t
p
,
size_t
align
)
{
return
p
&
~
(
align
-
1
);
}
static
constexpr
uintptr_t
align_up
(
uintptr_t
p
,
size_t
align
)
{
return
(
p
+
align
-
1
)
&
~
(
align
-
1
);
}
template
<
typename
T
>
static
inline
T
*
align_down
(
T
*
p
,
size_t
align
)
{
return
reinterpret_cast
<
T
*>
(
align_down
(
reinterpret_cast
<
uintptr_t
>
(
p
),
align
));
}
template
<
typename
T
>
static
inline
T
*
align_up
(
T
*
p
,
size_t
align
)
{
return
reinterpret_cast
<
T
*>
(
align_up
(
reinterpret_cast
<
uintptr_t
>
(
p
),
align
));
}
#if defined(__arm__)
// Do not emit anything for arm, clang does not allow emiting an arm unwind
// directive.
// #define BIONIC_STOP_UNWIND asm volatile(".cantunwind")
#define BIONIC_STOP_UNWIND
#elif defined(__aarch64__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined x30")
#elif defined(__i386__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined \%eip")
#elif defined(__x86_64__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined \%rip")
#elif defined (__mips__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined $ra")
#endif
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// One caveat is that arraysize() doesn't accept any array of an
// anonymous type or a type defined inside a function.
//
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template
<
typename
T
,
size_t
N
>
char
(
&
ArraySizeHelper
(
T
(
&
array
)[
N
]))[
N
];
// NOLINT(readability/casting)
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// Used to inform clang's -Wimplicit-fallthrough that a fallthrough is intended. There's no way to
// silence (or enable, apparently) -Wimplicit-fallthrough in C yet.
#ifdef __cplusplus
#define __BIONIC_FALLTHROUGH [[clang::fallthrough]]
#else
#define __BIONIC_FALLTHROUGH
#endif
#endif // _BIONIC_MACROS_H_
native/jni/resetprop/libsystemproperties/include/property_info_parser/property_info_parser.h
0 → 100644
View file @
7a002567
//
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef PROPERTY_INFO_PARSER_H
#define PROPERTY_INFO_PARSER_H
#include <stdint.h>
#include <stdlib.h>
namespace
android
{
namespace
properties
{
// The below structs intentionally do not end with char name[0] or other tricks to allocate
// with a dynamic size, such that they can be added onto in the future without breaking
// backwards compatibility.
struct
PropertyEntry
{
uint32_t
name_offset
;
uint32_t
namelen
;
// This is the context match for this node_; ~0u if it doesn't correspond to any.
uint32_t
context_index
;
// This is the type for this node_; ~0u if it doesn't correspond to any.
uint32_t
type_index
;
};
struct
TrieNodeInternal
{
// This points to a property entry struct, which includes the name for this node
uint32_t
property_entry
;
// Children are a sorted list of child nodes_; binary search them.
uint32_t
num_child_nodes
;
uint32_t
child_nodes
;
// Prefixes are terminating prefix matches at this node, sorted longest to smallest
// Take the first match sequentially found with StartsWith().
uint32_t
num_prefixes
;
uint32_t
prefix_entries
;
// Exact matches are a sorted list of exact matches at this node_; binary search them.
uint32_t
num_exact_matches
;
uint32_t
exact_match_entries
;
};
struct
PropertyInfoAreaHeader
{
// The current version of this data as created by property service.
uint32_t
current_version
;
// The lowest version of libc that can properly parse this data.
uint32_t
minimum_supported_version
;
uint32_t
size
;
uint32_t
contexts_offset
;
uint32_t
types_offset
;
uint32_t
root_offset
;
};
class
SerializedData
{
public
:
uint32_t
size
()
const
{
return
reinterpret_cast
<
const
PropertyInfoAreaHeader
*>
(
data_base_
)
->
size
;
}
const
char
*
c_string
(
uint32_t
offset
)
const
{
if
(
offset
!=
0
&&
offset
>
size
())
return
nullptr
;
return
static_cast
<
const
char
*>
(
data_base_
+
offset
);
}
const
uint32_t
*
uint32_array
(
uint32_t
offset
)
const
{
if
(
offset
!=
0
&&
offset
>
size
())
return
nullptr
;
return
reinterpret_cast
<
const
uint32_t
*>
(
data_base_
+
offset
);
}
uint32_t
uint32
(
uint32_t
offset
)
const
{
if
(
offset
!=
0
&&
offset
>
size
())
return
~
0u
;
return
*
reinterpret_cast
<
const
uint32_t
*>
(
data_base_
+
offset
);
}
const
char
*
data_base
()
const
{
return
data_base_
;
}
private
:
const
char
data_base_
[
0
];
};
class
TrieNode
{
public
:
TrieNode
()
:
serialized_data_
(
nullptr
),
trie_node_base_
(
nullptr
)
{}
TrieNode
(
const
SerializedData
*
data_base
,
const
TrieNodeInternal
*
trie_node_base
)
:
serialized_data_
(
data_base
),
trie_node_base_
(
trie_node_base
)
{}
const
char
*
name
()
const
{
return
serialized_data_
->
c_string
(
node_property_entry
()
->
name_offset
);
}
uint32_t
context_index
()
const
{
return
node_property_entry
()
->
context_index
;
}
uint32_t
type_index
()
const
{
return
node_property_entry
()
->
type_index
;
}
uint32_t
num_child_nodes
()
const
{
return
trie_node_base_
->
num_child_nodes
;
}
TrieNode
child_node
(
int
n
)
const
{
uint32_t
child_node_offset
=
serialized_data_
->
uint32_array
(
trie_node_base_
->
child_nodes
)[
n
];
const
TrieNodeInternal
*
trie_node_base
=
reinterpret_cast
<
const
TrieNodeInternal
*>
(
serialized_data_
->
data_base
()
+
child_node_offset
);
return
TrieNode
(
serialized_data_
,
trie_node_base
);
}
bool
FindChildForString
(
const
char
*
input
,
uint32_t
namelen
,
TrieNode
*
child
)
const
;
uint32_t
num_prefixes
()
const
{
return
trie_node_base_
->
num_prefixes
;
}
const
PropertyEntry
*
prefix
(
int
n
)
const
{
uint32_t
prefix_entry_offset
=
serialized_data_
->
uint32_array
(
trie_node_base_
->
prefix_entries
)[
n
];
return
reinterpret_cast
<
const
PropertyEntry
*>
(
serialized_data_
->
data_base
()
+
prefix_entry_offset
);
}
uint32_t
num_exact_matches
()
const
{
return
trie_node_base_
->
num_exact_matches
;
}
const
PropertyEntry
*
exact_match
(
int
n
)
const
{
uint32_t
exact_match_entry_offset
=
serialized_data_
->
uint32_array
(
trie_node_base_
->
exact_match_entries
)[
n
];
return
reinterpret_cast
<
const
PropertyEntry
*>
(
serialized_data_
->
data_base
()
+
exact_match_entry_offset
);
}
private
:
const
PropertyEntry
*
node_property_entry
()
const
{
return
reinterpret_cast
<
const
PropertyEntry
*>
(
serialized_data_
->
data_base
()
+
trie_node_base_
->
property_entry
);
}
const
SerializedData
*
serialized_data_
;
const
TrieNodeInternal
*
trie_node_base_
;
};
class
PropertyInfoArea
:
private
SerializedData
{
public
:
void
GetPropertyInfoIndexes
(
const
char
*
name
,
uint32_t
*
context_index
,
uint32_t
*
type_index
)
const
;
void
GetPropertyInfo
(
const
char
*
property
,
const
char
**
context
,
const
char
**
type
)
const
;
int
FindContextIndex
(
const
char
*
context
)
const
;
int
FindTypeIndex
(
const
char
*
type
)
const
;
const
char
*
context
(
uint32_t
index
)
const
{
uint32_t
context_array_size_offset
=
contexts_offset
();
const
uint32_t
*
context_array
=
uint32_array
(
context_array_size_offset
+
sizeof
(
uint32_t
));
return
data_base
()
+
context_array
[
index
];
}
const
char
*
type
(
uint32_t
index
)
const
{
uint32_t
type_array_size_offset
=
types_offset
();
const
uint32_t
*
type_array
=
uint32_array
(
type_array_size_offset
+
sizeof
(
uint32_t
));
return
data_base
()
+
type_array
[
index
];
}
uint32_t
current_version
()
const
{
return
header
()
->
current_version
;
}
uint32_t
minimum_supported_version
()
const
{
return
header
()
->
minimum_supported_version
;
}
uint32_t
size
()
const
{
return
SerializedData
::
size
();
}
uint32_t
num_contexts
()
const
{
return
uint32_array
(
contexts_offset
())[
0
];
}
uint32_t
num_types
()
const
{
return
uint32_array
(
types_offset
())[
0
];
}
TrieNode
root_node
()
const
{
return
trie
(
header
()
->
root_offset
);
}
private
:
void
CheckPrefixMatch
(
const
char
*
remaining_name
,
const
TrieNode
&
trie_node
,
uint32_t
*
context_index
,
uint32_t
*
type_index
)
const
;
const
PropertyInfoAreaHeader
*
header
()
const
{
return
reinterpret_cast
<
const
PropertyInfoAreaHeader
*>
(
data_base
());
}
uint32_t
contexts_offset
()
const
{
return
header
()
->
contexts_offset
;
}
uint32_t
contexts_array_offset
()
const
{
return
contexts_offset
()
+
sizeof
(
uint32_t
);
}
uint32_t
types_offset
()
const
{
return
header
()
->
types_offset
;
}
uint32_t
types_array_offset
()
const
{
return
types_offset
()
+
sizeof
(
uint32_t
);
}
TrieNode
trie
(
uint32_t
offset
)
const
{
if
(
offset
!=
0
&&
offset
>
size
())
return
TrieNode
();
const
TrieNodeInternal
*
trie_node_base
=
reinterpret_cast
<
const
TrieNodeInternal
*>
(
data_base
()
+
offset
);
return
TrieNode
(
this
,
trie_node_base
);
}
};
// This is essentially a smart pointer for read only mmap region for property contexts.
class
PropertyInfoAreaFile
{
public
:
PropertyInfoAreaFile
()
:
mmap_base_
(
nullptr
),
mmap_size_
(
0
)
{}
~
PropertyInfoAreaFile
()
{
Reset
();
}
PropertyInfoAreaFile
(
const
PropertyInfoAreaFile
&
)
=
delete
;
void
operator
=
(
const
PropertyInfoAreaFile
&
)
=
delete
;
PropertyInfoAreaFile
(
PropertyInfoAreaFile
&&
)
=
default
;
PropertyInfoAreaFile
&
operator
=
(
PropertyInfoAreaFile
&&
)
=
default
;
bool
LoadDefaultPath
();
bool
LoadPath
(
const
char
*
filename
);
const
PropertyInfoArea
*
operator
->
()
const
{
return
reinterpret_cast
<
const
PropertyInfoArea
*>
(
mmap_base_
);
}
explicit
operator
bool
()
const
{
return
mmap_base_
!=
nullptr
;
}
void
Reset
();
private
:
void
*
mmap_base_
;
size_t
mmap_size_
;
};
}
// namespace properties
}
// namespace android
#endif
native/jni/resetprop/libsystemproperties/include/system_properties/context_node.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include "private/bionic_lock.h"
#include "prop_area.h"
class
ContextNode
{
public
:
ContextNode
(
const
char
*
context
,
const
char
*
filename
)
:
context_
(
context
),
pa_
(
nullptr
),
no_access_
(
false
),
filename_
(
filename
)
{
lock_
.
init
(
false
);
}
~
ContextNode
()
{
Unmap
();
}
DISALLOW_COPY_AND_ASSIGN
(
ContextNode
);
bool
Open
(
bool
access_rw
,
bool
*
fsetxattr_failed
);
bool
CheckAccessAndOpen
();
void
ResetAccess
();
void
Unmap
();
const
char
*
context
()
const
{
return
context_
;
}
prop_area
*
pa
()
{
return
pa_
;
}
private
:
bool
CheckAccess
();
Lock
lock_
;
const
char
*
context_
;
prop_area
*
pa_
;
bool
no_access_
;
const
char
*
filename_
;
};
native/jni/resetprop/libsystemproperties/include/system_properties/contexts.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include "prop_area.h"
#include "prop_info.h"
class
Contexts
{
public
:
virtual
~
Contexts
()
{
}
virtual
bool
Initialize
(
bool
writable
,
const
char
*
filename
,
bool
*
fsetxattr_failed
)
=
0
;
virtual
prop_area
*
GetPropAreaForName
(
const
char
*
name
)
=
0
;
virtual
prop_area
*
GetSerialPropArea
()
=
0
;
virtual
void
ForEach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
=
0
;
virtual
void
ResetAccess
()
=
0
;
virtual
void
FreeAndUnmap
()
=
0
;
};
native/jni/resetprop/libsystemproperties/include/system_properties/contexts_pre_split.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include "contexts.h"
#include "prop_area.h"
#include "prop_info.h"
class
ContextsPreSplit
:
public
Contexts
{
public
:
virtual
~
ContextsPreSplit
()
override
{
}
// We'll never initialize this legacy option as writable, so don't even check the arg.
virtual
bool
Initialize
(
bool
,
const
char
*
filename
,
bool
*
)
override
{
pre_split_prop_area_
=
prop_area
::
map_prop_area
(
filename
);
return
pre_split_prop_area_
!=
nullptr
;
}
virtual
prop_area
*
GetPropAreaForName
(
const
char
*
)
override
{
return
pre_split_prop_area_
;
}
virtual
prop_area
*
GetSerialPropArea
()
override
{
return
pre_split_prop_area_
;
}
virtual
void
ForEach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
override
{
pre_split_prop_area_
->
foreach
(
propfn
,
cookie
);
}
// 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
{
}
virtual
void
FreeAndUnmap
()
override
{
prop_area
::
unmap_prop_area
(
&
pre_split_prop_area_
);
}
private
:
prop_area
*
pre_split_prop_area_
=
nullptr
;
};
native/jni/resetprop/libsystemproperties/include/system_properties/contexts_serialized.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include <property_info_parser/property_info_parser.h>
#include "context_node.h"
#include "contexts.h"
class
ContextsSerialized
:
public
Contexts
{
public
:
virtual
~
ContextsSerialized
()
override
{
}
virtual
bool
Initialize
(
bool
writable
,
const
char
*
filename
,
bool
*
fsetxattr_failed
)
override
;
virtual
prop_area
*
GetPropAreaForName
(
const
char
*
name
)
override
;
virtual
prop_area
*
GetSerialPropArea
()
override
{
return
serial_prop_area_
;
}
virtual
void
ForEach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
override
;
virtual
void
ResetAccess
()
override
;
virtual
void
FreeAndUnmap
()
override
;
private
:
bool
InitializeContextNodes
();
bool
InitializeProperties
();
bool
MapSerialPropertyArea
(
bool
access_rw
,
bool
*
fsetxattr_failed
);
const
char
*
filename_
;
android
::
properties
::
PropertyInfoAreaFile
property_info_area_file_
;
ContextNode
*
context_nodes_
=
nullptr
;
size_t
num_context_nodes_
=
0
;
size_t
context_nodes_mmap_size_
=
0
;
prop_area
*
serial_prop_area_
=
nullptr
;
};
native/jni/resetprop/libsystemproperties/include/system_properties/contexts_split.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include "contexts.h"
struct
PrefixNode
;
class
ContextListNode
;
class
ContextsSplit
:
public
Contexts
{
public
:
virtual
~
ContextsSplit
()
override
{
}
virtual
bool
Initialize
(
bool
writable
,
const
char
*
filename
,
bool
*
fsetxattr_failed
)
override
;
virtual
prop_area
*
GetPropAreaForName
(
const
char
*
name
)
override
;
virtual
prop_area
*
GetSerialPropArea
()
override
{
return
serial_prop_area_
;
}
virtual
void
ForEach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
override
;
virtual
void
ResetAccess
()
override
;
virtual
void
FreeAndUnmap
()
override
;
private
:
bool
MapSerialPropertyArea
(
bool
access_rw
,
bool
*
fsetxattr_failed
);
bool
InitializePropertiesFromFile
(
const
char
*
filename
);
bool
InitializeProperties
();
PrefixNode
*
prefixes_
=
nullptr
;
ContextListNode
*
contexts_
=
nullptr
;
prop_area
*
serial_prop_area_
=
nullptr
;
const
char
*
filename_
=
nullptr
;
};
native/jni/resetprop/libsystemproperties/include/system_properties/prop_area.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include <stdatomic.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include "private/bionic_macros.h"
#include "prop_info.h"
// Properties are stored in a hybrid trie/binary tree structure.
// Each property's name is delimited at '.' characters, and the tokens are put
// into a trie structure. Siblings at each level of the trie are stored in a
// binary tree. For instance, "ro.secure"="1" could be stored as follows:
//
// +-----+ children +----+ children +--------+
// | |-------------->| ro |-------------->| secure |
// +-----+ +----+ +--------+
// / \ / |
// left / \ right left / | prop +===========+
// v v v +-------->| ro.secure |
// +-----+ +-----+ +-----+ +-----------+
// | net | | sys | | com | | 1 |
// +-----+ +-----+ +-----+ +===========+
// Represents a node in the trie.
struct
prop_bt
{
uint32_t
namelen
;
// The property trie is updated only by the init process (single threaded) which provides
// property service. And it can be read by multiple threads at the same time.
// As the property trie is not protected by locks, we use atomic_uint_least32_t types for the
// left, right, children "pointers" in the trie node. To make sure readers who see the
// change of "pointers" can also notice the change of prop_bt structure contents pointed by
// the "pointers", we always use release-consume ordering pair when accessing these "pointers".
// prop "points" to prop_info structure if there is a propery associated with the trie node.
// Its situation is similar to the left, right, children "pointers". So we use
// atomic_uint_least32_t and release-consume ordering to protect it as well.
// We should also avoid rereading these fields redundantly, since not
// all processor implementations ensure that multiple loads from the
// same field are carried out in the right order.
atomic_uint_least32_t
prop
;
atomic_uint_least32_t
left
;
atomic_uint_least32_t
right
;
atomic_uint_least32_t
children
;
char
name
[
0
];
prop_bt
(
const
char
*
name
,
const
uint32_t
name_length
)
{
this
->
namelen
=
name_length
;
memcpy
(
this
->
name
,
name
,
name_length
);
this
->
name
[
name_length
]
=
'\0'
;
}
private
:
DISALLOW_COPY_AND_ASSIGN
(
prop_bt
);
};
class
prop_area
{
public
:
static
prop_area
*
map_prop_area_rw
(
const
char
*
filename
,
const
char
*
context
,
bool
*
fsetxattr_failed
);
static
prop_area
*
map_prop_area
(
const
char
*
filename
);
static
void
unmap_prop_area
(
prop_area
**
pa
)
{
if
(
*
pa
)
{
munmap
(
*
pa
,
pa_size_
);
*
pa
=
nullptr
;
}
}
prop_area
(
const
uint32_t
magic
,
const
uint32_t
version
)
:
magic_
(
magic
),
version_
(
version
)
{
atomic_init
(
&
serial_
,
0u
);
memset
(
reserved_
,
0
,
sizeof
(
reserved_
));
// Allocate enough space for the root node.
bytes_used_
=
sizeof
(
prop_bt
);
}
const
prop_info
*
find
(
const
char
*
name
);
bool
add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
);
bool
foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
);
atomic_uint_least32_t
*
serial
()
{
return
&
serial_
;
}
uint32_t
magic
()
const
{
return
magic_
;
}
uint32_t
version
()
const
{
return
version_
;
}
private
:
static
prop_area
*
map_fd_ro
(
const
int
fd
);
void
*
allocate_obj
(
const
size_t
size
,
uint_least32_t
*
const
off
);
prop_bt
*
new_prop_bt
(
const
char
*
name
,
uint32_t
namelen
,
uint_least32_t
*
const
off
);
prop_info
*
new_prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
uint_least32_t
*
const
off
);
void
*
to_prop_obj
(
uint_least32_t
off
);
prop_bt
*
to_prop_bt
(
atomic_uint_least32_t
*
off_p
);
prop_info
*
to_prop_info
(
atomic_uint_least32_t
*
off_p
);
prop_bt
*
root_node
();
prop_bt
*
find_prop_bt
(
prop_bt
*
const
bt
,
const
char
*
name
,
uint32_t
namelen
,
bool
alloc_if_needed
);
const
prop_info
*
find_property
(
prop_bt
*
const
trie
,
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
bool
alloc_if_needed
);
bool
foreach_property
(
prop_bt
*
const
trie
,
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
);
// The original design doesn't include pa_size or pa_data_size in the prop_area struct itself.
// Since we'll need to be backwards compatible with that design, we don't gain much by adding it
// now, especially since we don't have any plans to make different property areas different sizes,
// and thus we share these two variables among all instances.
static
size_t
pa_size_
;
static
size_t
pa_data_size_
;
uint32_t
bytes_used_
;
atomic_uint_least32_t
serial_
;
uint32_t
magic_
;
uint32_t
version_
;
uint32_t
reserved_
[
28
];
char
data_
[
0
];
DISALLOW_COPY_AND_ASSIGN
(
prop_area
);
};
native/jni/resetprop/libsystemproperties/include/system_properties/prop_info.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include <stdatomic.h>
#include <stdint.h>
#include <sys/system_properties.h>
#include "private/bionic_macros.h"
#include "hacks.h"
// The C11 standard doesn't allow atomic loads from const fields,
// though C++11 does. Fudge it until standards get straightened out.
static
inline
uint_least32_t
load_const_atomic
(
const
atomic_uint_least32_t
*
s
,
memory_order
mo
)
{
atomic_uint_least32_t
*
non_const_s
=
const_cast
<
atomic_uint_least32_t
*>
(
s
);
return
atomic_load_explicit
(
non_const_s
,
mo
);
}
struct
prop_info
{
// Read only properties will not set anything but the bottom most bit of serial and the top byte.
// We borrow the 2nd from the top byte for extra flags, and use the bottom most bit of that for
// our first user, kLongFlag.
constexpr
static
uint32_t
kLongFlag
=
1
<<
16
;
// The error message fits in part of a union with the previous 92 char property value so there
// must be room left over after the error message for the offset to the new longer property value
// and future expansion fields if needed. Note that this value cannot ever increase. The offset
// to the new longer property value appears immediately after it, so an increase of this size will
// break compatibility.
constexpr
static
size_t
kLongLegacyErrorBufferSize
=
56
;
public
:
atomic_uint_least32_t
serial
;
// we need to keep this buffer around because the property
// value can be modified whereas name is constant.
union
{
char
value
[
PROP_VALUE_MAX
];
struct
{
char
error_message
[
kLongLegacyErrorBufferSize
];
uint32_t
offset
;
}
long_property
;
};
char
name
[
0
];
bool
is_long
()
const
{
return
(
load_const_atomic
(
&
serial
,
memory_order_relaxed
)
&
kLongFlag
)
!=
0
;
}
const
char
*
long_value
()
const
{
// We can't store pointers here since this is shared memory that will have different absolute
// pointers in different processes. We don't have data_ from prop_area, but since we know
// `this` is data_ + some offset and long_value is data_ + some other offset, we calculate the
// offset from `this` to long_value and store it as long_property.offset.
return
reinterpret_cast
<
const
char
*>
(
this
)
+
long_property
.
offset
;
}
prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
);
prop_info
(
const
char
*
name
,
uint32_t
namelen
,
uint32_t
long_offset
);
private
:
DISALLOW_IMPLICIT_CONSTRUCTORS
(
prop_info
);
};
static_assert
(
sizeof
(
prop_info
)
==
96
,
"sizeof struct prop_info must be 96 bytes"
);
native/jni/resetprop/libsystemproperties/include/system_properties/system_properties.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
#include <stdint.h>
#include <sys/param.h>
#include <sys/system_properties.h>
#include "contexts.h"
#include "contexts_pre_split.h"
#include "contexts_serialized.h"
#include "contexts_split.h"
constexpr
int
PROP_FILENAME_MAX
=
1024
;
class
SystemProperties
{
public
:
friend
struct
LocalPropertyTestState
;
friend
class
SystemPropertiesTest
;
// Note that system properties are initialized before libc calls static initializers, so
// doing any initialization in this constructor is an error. Even a Constructor that zero
// initializes this class will clobber the previous property initialization.
// We rely on the static SystemProperties in libc to be placed in .bss and zero initialized.
SystemProperties
()
=
default
;
// Special constructor for testing that also zero initializes the important members.
explicit
SystemProperties
(
bool
initialized
)
:
initialized_
(
initialized
)
{
}
DISALLOW_COPY_AND_ASSIGN
(
SystemProperties
);
bool
Init
(
const
char
*
filename
);
bool
AreaInit
(
const
char
*
filename
,
bool
*
fsetxattr_failed
);
uint32_t
AreaSerial
();
const
prop_info
*
Find
(
const
char
*
name
);
int
Read
(
const
prop_info
*
pi
,
char
*
name
,
char
*
value
);
void
ReadCallback
(
const
prop_info
*
pi
,
void
(
*
callback
)(
void
*
cookie
,
const
char
*
name
,
const
char
*
value
,
uint32_t
serial
),
void
*
cookie
);
int
Get
(
const
char
*
name
,
char
*
value
);
int
Update
(
prop_info
*
pi
,
const
char
*
value
,
unsigned
int
len
);
int
Add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
);
uint32_t
Serial
(
const
prop_info
*
pi
);
uint32_t
WaitAny
(
uint32_t
old_serial
);
bool
Wait
(
const
prop_info
*
pi
,
uint32_t
old_serial
,
uint32_t
*
new_serial_ptr
,
const
timespec
*
relative_timeout
);
const
prop_info
*
FindNth
(
unsigned
n
);
int
Foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
);
private
:
// We don't want to use new or malloc in properties (b/31659220), and we don't want to waste a
// full page by using mmap(), so we set aside enough space to create any context of the three
// contexts.
static
constexpr
size_t
kMaxContextsAlign
=
MAX
(
alignof
(
ContextsSerialized
),
MAX
(
alignof
(
ContextsSplit
),
alignof
(
ContextsPreSplit
)));
static
constexpr
size_t
kMaxContextsSize
=
MAX
(
sizeof
(
ContextsSerialized
),
MAX
(
sizeof
(
ContextsSplit
),
sizeof
(
ContextsPreSplit
)));
alignas
(
kMaxContextsAlign
)
char
contexts_data_
[
kMaxContextsSize
];
Contexts
*
contexts_
;
bool
initialized_
;
char
property_filename_
[
PROP_FILENAME_MAX
];
};
native/jni/resetprop/libsystemproperties/prop_area.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "system_properties/prop_area.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <unistd.h>
#include <new>
#include <async_safe/log.h>
constexpr
size_t
PA_SIZE
=
128
*
1024
;
constexpr
uint32_t
PROP_AREA_MAGIC
=
0x504f5250
;
constexpr
uint32_t
PROP_AREA_VERSION
=
0xfc6ed0ab
;
size_t
prop_area
::
pa_size_
=
0
;
size_t
prop_area
::
pa_data_size_
=
0
;
prop_area
*
prop_area
::
map_prop_area_rw
(
const
char
*
filename
,
const
char
*
context
,
bool
*
fsetxattr_failed
)
{
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
const
int
fd
=
open
(
filename
,
O_RDWR
|
O_CREAT
|
O_NOFOLLOW
|
O_CLOEXEC
|
O_EXCL
,
0444
);
if
(
fd
<
0
)
{
if
(
errno
==
EACCES
)
{
/* for consistency with the case where the process has already
* mapped the page in and segfaults when trying to write to it
*/
abort
();
}
return
nullptr
;
}
if
(
context
)
{
if
(
fsetxattr
(
fd
,
XATTR_NAME_SELINUX
,
context
,
strlen
(
context
)
+
1
,
0
)
!=
0
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"fsetxattr failed to set context (%s) for
\"
%s
\"
"
,
context
,
filename
);
/*
* fsetxattr() will fail during system properties tests due to selinux policy.
* We do not want to create a custom policy for the tester, so we will continue in
* this function but set a flag that an error has occurred.
* Init, which is the only daemon that should ever call this function will abort
* when this error occurs.
* Otherwise, the tester will ignore it and continue, albeit without any selinux
* property separation.
*/
if
(
fsetxattr_failed
)
{
*
fsetxattr_failed
=
true
;
}
}
}
if
(
ftruncate
(
fd
,
PA_SIZE
)
<
0
)
{
close
(
fd
);
return
nullptr
;
}
pa_size_
=
PA_SIZE
;
pa_data_size_
=
pa_size_
-
sizeof
(
prop_area
);
void
*
const
memory_area
=
mmap
(
nullptr
,
pa_size_
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
if
(
memory_area
==
MAP_FAILED
)
{
close
(
fd
);
return
nullptr
;
}
prop_area
*
pa
=
new
(
memory_area
)
prop_area
(
PROP_AREA_MAGIC
,
PROP_AREA_VERSION
);
close
(
fd
);
return
pa
;
}
prop_area
*
prop_area
::
map_fd_ro
(
const
int
fd
)
{
struct
stat
fd_stat
;
if
(
fstat
(
fd
,
&
fd_stat
)
<
0
)
{
return
nullptr
;
}
if
((
fd_stat
.
st_uid
!=
0
)
||
(
fd_stat
.
st_gid
!=
0
)
||
((
fd_stat
.
st_mode
&
(
S_IWGRP
|
S_IWOTH
))
!=
0
)
||
(
fd_stat
.
st_size
<
static_cast
<
off_t
>
(
sizeof
(
prop_area
))))
{
return
nullptr
;
}
pa_size_
=
fd_stat
.
st_size
;
pa_data_size_
=
pa_size_
-
sizeof
(
prop_area
);
void
*
const
map_result
=
mmap
(
nullptr
,
pa_size_
,
PROT_READ
,
MAP_SHARED
,
fd
,
0
);
if
(
map_result
==
MAP_FAILED
)
{
return
nullptr
;
}
prop_area
*
pa
=
reinterpret_cast
<
prop_area
*>
(
map_result
);
if
((
pa
->
magic
()
!=
PROP_AREA_MAGIC
)
||
(
pa
->
version
()
!=
PROP_AREA_VERSION
))
{
munmap
(
pa
,
pa_size_
);
return
nullptr
;
}
return
pa
;
}
prop_area
*
prop_area
::
map_prop_area
(
const
char
*
filename
)
{
int
fd
=
open
(
filename
,
O_CLOEXEC
|
O_NOFOLLOW
|
O_RDONLY
);
if
(
fd
==
-
1
)
return
nullptr
;
prop_area
*
map_result
=
map_fd_ro
(
fd
);
close
(
fd
);
return
map_result
;
}
void
*
prop_area
::
allocate_obj
(
const
size_t
size
,
uint_least32_t
*
const
off
)
{
const
size_t
aligned
=
__BIONIC_ALIGN
(
size
,
sizeof
(
uint_least32_t
));
if
(
bytes_used_
+
aligned
>
pa_data_size_
)
{
return
nullptr
;
}
*
off
=
bytes_used_
;
bytes_used_
+=
aligned
;
return
data_
+
*
off
;
}
prop_bt
*
prop_area
::
new_prop_bt
(
const
char
*
name
,
uint32_t
namelen
,
uint_least32_t
*
const
off
)
{
uint_least32_t
new_offset
;
void
*
const
p
=
allocate_obj
(
sizeof
(
prop_bt
)
+
namelen
+
1
,
&
new_offset
);
if
(
p
!=
nullptr
)
{
prop_bt
*
bt
=
new
(
p
)
prop_bt
(
name
,
namelen
);
*
off
=
new_offset
;
return
bt
;
}
return
nullptr
;
}
prop_info
*
prop_area
::
new_prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
uint_least32_t
*
const
off
)
{
uint_least32_t
new_offset
;
void
*
const
p
=
allocate_obj
(
sizeof
(
prop_info
)
+
namelen
+
1
,
&
new_offset
);
if
(
p
==
nullptr
)
return
nullptr
;
prop_info
*
info
;
if
(
valuelen
>=
PROP_VALUE_MAX
)
{
uint32_t
long_value_offset
=
0
;
char
*
long_location
=
reinterpret_cast
<
char
*>
(
allocate_obj
(
valuelen
+
1
,
&
long_value_offset
));
if
(
!
long_location
)
return
nullptr
;
memcpy
(
long_location
,
value
,
valuelen
);
long_location
[
valuelen
]
=
'\0'
;
// Both new_offset and long_value_offset are offsets based off of data_, however prop_info
// does not know what data_ is, so we change this offset to be an offset from the prop_info
// pointer that contains it.
long_value_offset
-=
new_offset
;
info
=
new
(
p
)
prop_info
(
name
,
namelen
,
long_value_offset
);
}
else
{
info
=
new
(
p
)
prop_info
(
name
,
namelen
,
value
,
valuelen
);
}
*
off
=
new_offset
;
return
info
;
}
void
*
prop_area
::
to_prop_obj
(
uint_least32_t
off
)
{
if
(
off
>
pa_data_size_
)
return
nullptr
;
return
(
data_
+
off
);
}
inline
prop_bt
*
prop_area
::
to_prop_bt
(
atomic_uint_least32_t
*
off_p
)
{
uint_least32_t
off
=
atomic_load_explicit
(
off_p
,
memory_order_consume
);
return
reinterpret_cast
<
prop_bt
*>
(
to_prop_obj
(
off
));
}
inline
prop_info
*
prop_area
::
to_prop_info
(
atomic_uint_least32_t
*
off_p
)
{
uint_least32_t
off
=
atomic_load_explicit
(
off_p
,
memory_order_consume
);
return
reinterpret_cast
<
prop_info
*>
(
to_prop_obj
(
off
));
}
inline
prop_bt
*
prop_area
::
root_node
()
{
return
reinterpret_cast
<
prop_bt
*>
(
to_prop_obj
(
0
));
}
static
int
cmp_prop_name
(
const
char
*
one
,
uint32_t
one_len
,
const
char
*
two
,
uint32_t
two_len
)
{
if
(
one_len
<
two_len
)
return
-
1
;
else
if
(
one_len
>
two_len
)
return
1
;
else
return
strncmp
(
one
,
two
,
one_len
);
}
prop_bt
*
prop_area
::
find_prop_bt
(
prop_bt
*
const
bt
,
const
char
*
name
,
uint32_t
namelen
,
bool
alloc_if_needed
)
{
prop_bt
*
current
=
bt
;
while
(
true
)
{
if
(
!
current
)
{
return
nullptr
;
}
const
int
ret
=
cmp_prop_name
(
name
,
namelen
,
current
->
name
,
current
->
namelen
);
if
(
ret
==
0
)
{
return
current
;
}
if
(
ret
<
0
)
{
uint_least32_t
left_offset
=
atomic_load_explicit
(
&
current
->
left
,
memory_order_relaxed
);
if
(
left_offset
!=
0
)
{
current
=
to_prop_bt
(
&
current
->
left
);
}
else
{
if
(
!
alloc_if_needed
)
{
return
nullptr
;
}
uint_least32_t
new_offset
;
prop_bt
*
new_bt
=
new_prop_bt
(
name
,
namelen
,
&
new_offset
);
if
(
new_bt
)
{
atomic_store_explicit
(
&
current
->
left
,
new_offset
,
memory_order_release
);
}
return
new_bt
;
}
}
else
{
uint_least32_t
right_offset
=
atomic_load_explicit
(
&
current
->
right
,
memory_order_relaxed
);
if
(
right_offset
!=
0
)
{
current
=
to_prop_bt
(
&
current
->
right
);
}
else
{
if
(
!
alloc_if_needed
)
{
return
nullptr
;
}
uint_least32_t
new_offset
;
prop_bt
*
new_bt
=
new_prop_bt
(
name
,
namelen
,
&
new_offset
);
if
(
new_bt
)
{
atomic_store_explicit
(
&
current
->
right
,
new_offset
,
memory_order_release
);
}
return
new_bt
;
}
}
}
}
const
prop_info
*
prop_area
::
find_property
(
prop_bt
*
const
trie
,
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
bool
alloc_if_needed
)
{
if
(
!
trie
)
return
nullptr
;
const
char
*
remaining_name
=
name
;
prop_bt
*
current
=
trie
;
while
(
true
)
{
const
char
*
sep
=
strchr
(
remaining_name
,
'.'
);
const
bool
want_subtree
=
(
sep
!=
nullptr
);
const
uint32_t
substr_size
=
(
want_subtree
)
?
sep
-
remaining_name
:
strlen
(
remaining_name
);
if
(
!
substr_size
)
{
return
nullptr
;
}
prop_bt
*
root
=
nullptr
;
uint_least32_t
children_offset
=
atomic_load_explicit
(
&
current
->
children
,
memory_order_relaxed
);
if
(
children_offset
!=
0
)
{
root
=
to_prop_bt
(
&
current
->
children
);
}
else
if
(
alloc_if_needed
)
{
uint_least32_t
new_offset
;
root
=
new_prop_bt
(
remaining_name
,
substr_size
,
&
new_offset
);
if
(
root
)
{
atomic_store_explicit
(
&
current
->
children
,
new_offset
,
memory_order_release
);
}
}
if
(
!
root
)
{
return
nullptr
;
}
current
=
find_prop_bt
(
root
,
remaining_name
,
substr_size
,
alloc_if_needed
);
if
(
!
current
)
{
return
nullptr
;
}
if
(
!
want_subtree
)
break
;
remaining_name
=
sep
+
1
;
}
uint_least32_t
prop_offset
=
atomic_load_explicit
(
&
current
->
prop
,
memory_order_relaxed
);
if
(
prop_offset
!=
0
)
{
return
to_prop_info
(
&
current
->
prop
);
}
else
if
(
alloc_if_needed
)
{
uint_least32_t
new_offset
;
prop_info
*
new_info
=
new_prop_info
(
name
,
namelen
,
value
,
valuelen
,
&
new_offset
);
if
(
new_info
)
{
atomic_store_explicit
(
&
current
->
prop
,
new_offset
,
memory_order_release
);
}
return
new_info
;
}
else
{
return
nullptr
;
}
}
bool
prop_area
::
foreach_property
(
prop_bt
*
const
trie
,
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
if
(
!
trie
)
return
false
;
uint_least32_t
left_offset
=
atomic_load_explicit
(
&
trie
->
left
,
memory_order_relaxed
);
if
(
left_offset
!=
0
)
{
const
int
err
=
foreach_property
(
to_prop_bt
(
&
trie
->
left
),
propfn
,
cookie
);
if
(
err
<
0
)
return
false
;
}
uint_least32_t
prop_offset
=
atomic_load_explicit
(
&
trie
->
prop
,
memory_order_relaxed
);
if
(
prop_offset
!=
0
)
{
prop_info
*
info
=
to_prop_info
(
&
trie
->
prop
);
if
(
!
info
)
return
false
;
propfn
(
info
,
cookie
);
}
uint_least32_t
children_offset
=
atomic_load_explicit
(
&
trie
->
children
,
memory_order_relaxed
);
if
(
children_offset
!=
0
)
{
const
int
err
=
foreach_property
(
to_prop_bt
(
&
trie
->
children
),
propfn
,
cookie
);
if
(
err
<
0
)
return
false
;
}
uint_least32_t
right_offset
=
atomic_load_explicit
(
&
trie
->
right
,
memory_order_relaxed
);
if
(
right_offset
!=
0
)
{
const
int
err
=
foreach_property
(
to_prop_bt
(
&
trie
->
right
),
propfn
,
cookie
);
if
(
err
<
0
)
return
false
;
}
return
true
;
}
const
prop_info
*
prop_area
::
find
(
const
char
*
name
)
{
return
find_property
(
root_node
(),
name
,
strlen
(
name
),
nullptr
,
0
,
false
);
}
bool
prop_area
::
add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
)
{
return
find_property
(
root_node
(),
name
,
namelen
,
value
,
valuelen
,
true
);
}
bool
prop_area
::
foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
return
foreach_property
(
root_node
(),
propfn
,
cookie
);
}
native/jni/resetprop/libsystemproperties/prop_info.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "system_properties/prop_info.h"
#include <string.h>
constexpr
static
const
char
kLongLegacyError
[]
=
"Must use __system_property_read_callback() to read"
;
static_assert
(
sizeof
(
kLongLegacyError
)
<
prop_info
::
kLongLegacyErrorBufferSize
,
"Error message for long properties read by legacy libc must fit within 56 chars"
);
prop_info
::
prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
)
{
memcpy
(
this
->
name
,
name
,
namelen
);
this
->
name
[
namelen
]
=
'\0'
;
atomic_init
(
&
this
->
serial
,
valuelen
<<
24
);
memcpy
(
this
->
value
,
value
,
valuelen
);
this
->
value
[
valuelen
]
=
'\0'
;
}
prop_info
::
prop_info
(
const
char
*
name
,
uint32_t
namelen
,
uint32_t
long_offset
)
{
memcpy
(
this
->
name
,
name
,
namelen
);
this
->
name
[
namelen
]
=
'\0'
;
auto
error_value_len
=
sizeof
(
kLongLegacyError
)
-
1
;
atomic_init
(
&
this
->
serial
,
error_value_len
<<
24
|
kLongFlag
);
memcpy
(
this
->
long_property
.
error_message
,
kLongLegacyError
,
sizeof
(
kLongLegacyError
));
this
->
long_property
.
offset
=
long_offset
;
}
native/jni/resetprop/libsystemproperties/property_info_parser.cpp
0 → 100644
View file @
7a002567
//
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "property_info_parser/property_info_parser.h"
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace
android
{
namespace
properties
{
namespace
{
// Binary search to find index of element in an array compared via f(search).
template
<
typename
F
>
int
Find
(
uint32_t
array_length
,
F
&&
f
)
{
int
bottom
=
0
;
int
top
=
array_length
-
1
;
while
(
top
>=
bottom
)
{
int
search
=
(
top
+
bottom
)
/
2
;
auto
cmp
=
f
(
search
);
if
(
cmp
==
0
)
return
search
;
if
(
cmp
<
0
)
bottom
=
search
+
1
;
if
(
cmp
>
0
)
top
=
search
-
1
;
}
return
-
1
;
}
}
// namespace
// Binary search the list of contexts to find the index of a given context string.
// Only should be used for TrieSerializer to construct the Trie.
int
PropertyInfoArea
::
FindContextIndex
(
const
char
*
context
)
const
{
return
Find
(
num_contexts
(),
[
this
,
context
](
auto
array_offset
)
{
auto
string_offset
=
uint32_array
(
contexts_array_offset
())[
array_offset
];
return
strcmp
(
c_string
(
string_offset
),
context
);
});
}
// Binary search the list of types to find the index of a given type string.
// Only should be used for TrieSerializer to construct the Trie.
int
PropertyInfoArea
::
FindTypeIndex
(
const
char
*
type
)
const
{
return
Find
(
num_types
(),
[
this
,
type
](
auto
array_offset
)
{
auto
string_offset
=
uint32_array
(
types_array_offset
())[
array_offset
];
return
strcmp
(
c_string
(
string_offset
),
type
);
});
}
// Binary search the list of children nodes to find a TrieNode for a given property piece.
// Used to traverse the Trie in GetPropertyInfoIndexes().
bool
TrieNode
::
FindChildForString
(
const
char
*
name
,
uint32_t
namelen
,
TrieNode
*
child
)
const
{
auto
node_index
=
Find
(
trie_node_base_
->
num_child_nodes
,
[
this
,
name
,
namelen
](
auto
array_offset
)
{
const
char
*
child_name
=
child_node
(
array_offset
).
name
();
int
cmp
=
strncmp
(
child_name
,
name
,
namelen
);
if
(
cmp
==
0
&&
child_name
[
namelen
]
!=
'\0'
)
{
// We use strncmp() since name isn't null terminated, but we don't want to match only a
// prefix of a child node's name, so we check here if we did only match a prefix and
// return 1, to indicate to the binary search to search earlier in the array for the real
// match.
return
1
;
}
return
cmp
;
});
if
(
node_index
==
-
1
)
{
return
false
;
}
*
child
=
child_node
(
node_index
);
return
true
;
}
void
PropertyInfoArea
::
CheckPrefixMatch
(
const
char
*
remaining_name
,
const
TrieNode
&
trie_node
,
uint32_t
*
context_index
,
uint32_t
*
type_index
)
const
{
const
uint32_t
remaining_name_size
=
strlen
(
remaining_name
);
for
(
uint32_t
i
=
0
;
i
<
trie_node
.
num_prefixes
();
++
i
)
{
auto
prefix_len
=
trie_node
.
prefix
(
i
)
->
namelen
;
if
(
prefix_len
>
remaining_name_size
)
continue
;
if
(
!
strncmp
(
c_string
(
trie_node
.
prefix
(
i
)
->
name_offset
),
remaining_name
,
prefix_len
))
{
if
(
trie_node
.
prefix
(
i
)
->
context_index
!=
~
0u
)
{
*
context_index
=
trie_node
.
prefix
(
i
)
->
context_index
;
}
if
(
trie_node
.
prefix
(
i
)
->
type_index
!=
~
0u
)
{
*
type_index
=
trie_node
.
prefix
(
i
)
->
type_index
;
}
return
;
}
}
}
void
PropertyInfoArea
::
GetPropertyInfoIndexes
(
const
char
*
name
,
uint32_t
*
context_index
,
uint32_t
*
type_index
)
const
{
uint32_t
return_context_index
=
~
0u
;
uint32_t
return_type_index
=
~
0u
;
const
char
*
remaining_name
=
name
;
auto
trie_node
=
root_node
();
while
(
true
)
{
const
char
*
sep
=
strchr
(
remaining_name
,
'.'
);
// Apply prefix match for prefix deliminated with '.'
if
(
trie_node
.
context_index
()
!=
~
0u
)
{
return_context_index
=
trie_node
.
context_index
();
}
if
(
trie_node
.
type_index
()
!=
~
0u
)
{
return_type_index
=
trie_node
.
type_index
();
}
// Check prefixes at this node. This comes after the node check since these prefixes are by
// definition longer than the node itself.
CheckPrefixMatch
(
remaining_name
,
trie_node
,
&
return_context_index
,
&
return_type_index
);
if
(
sep
==
nullptr
)
{
break
;
}
const
uint32_t
substr_size
=
sep
-
remaining_name
;
TrieNode
child_node
;
if
(
!
trie_node
.
FindChildForString
(
remaining_name
,
substr_size
,
&
child_node
))
{
break
;
}
trie_node
=
child_node
;
remaining_name
=
sep
+
1
;
}
// We've made it to a leaf node, so check contents and return appropriately.
// Check exact matches
for
(
uint32_t
i
=
0
;
i
<
trie_node
.
num_exact_matches
();
++
i
)
{
if
(
!
strcmp
(
c_string
(
trie_node
.
exact_match
(
i
)
->
name_offset
),
remaining_name
))
{
if
(
context_index
!=
nullptr
)
{
if
(
trie_node
.
exact_match
(
i
)
->
context_index
!=
~
0u
)
{
*
context_index
=
trie_node
.
exact_match
(
i
)
->
context_index
;
}
else
{
*
context_index
=
return_context_index
;
}
}
if
(
type_index
!=
nullptr
)
{
if
(
trie_node
.
exact_match
(
i
)
->
type_index
!=
~
0u
)
{
*
type_index
=
trie_node
.
exact_match
(
i
)
->
type_index
;
}
else
{
*
type_index
=
return_type_index
;
}
}
return
;
}
}
// Check prefix matches for prefixes not deliminated with '.'
CheckPrefixMatch
(
remaining_name
,
trie_node
,
&
return_context_index
,
&
return_type_index
);
// Return previously found prefix match.
if
(
context_index
!=
nullptr
)
*
context_index
=
return_context_index
;
if
(
type_index
!=
nullptr
)
*
type_index
=
return_type_index
;
return
;
}
void
PropertyInfoArea
::
GetPropertyInfo
(
const
char
*
property
,
const
char
**
context
,
const
char
**
type
)
const
{
uint32_t
context_index
;
uint32_t
type_index
;
GetPropertyInfoIndexes
(
property
,
&
context_index
,
&
type_index
);
if
(
context
!=
nullptr
)
{
if
(
context_index
==
~
0u
)
{
*
context
=
nullptr
;
}
else
{
*
context
=
this
->
context
(
context_index
);
}
}
if
(
type
!=
nullptr
)
{
if
(
type_index
==
~
0u
)
{
*
type
=
nullptr
;
}
else
{
*
type
=
this
->
type
(
type_index
);
}
}
}
bool
PropertyInfoAreaFile
::
LoadDefaultPath
()
{
return
LoadPath
(
"/dev/__properties__/property_info"
);
}
bool
PropertyInfoAreaFile
::
LoadPath
(
const
char
*
filename
)
{
int
fd
=
open
(
filename
,
O_CLOEXEC
|
O_NOFOLLOW
|
O_RDONLY
);
struct
stat
fd_stat
;
if
(
fstat
(
fd
,
&
fd_stat
)
<
0
)
{
close
(
fd
);
return
false
;
}
if
((
fd_stat
.
st_uid
!=
0
)
||
(
fd_stat
.
st_gid
!=
0
)
||
((
fd_stat
.
st_mode
&
(
S_IWGRP
|
S_IWOTH
))
!=
0
)
||
(
fd_stat
.
st_size
<
static_cast
<
off_t
>
(
sizeof
(
PropertyInfoArea
))))
{
close
(
fd
);
return
false
;
}
auto
mmap_size
=
fd_stat
.
st_size
;
void
*
map_result
=
mmap
(
nullptr
,
mmap_size
,
PROT_READ
,
MAP_SHARED
,
fd
,
0
);
if
(
map_result
==
MAP_FAILED
)
{
close
(
fd
);
return
false
;
}
auto
property_info_area
=
reinterpret_cast
<
PropertyInfoArea
*>
(
map_result
);
if
(
property_info_area
->
minimum_supported_version
()
>
1
||
property_info_area
->
size
()
!=
mmap_size
)
{
munmap
(
map_result
,
mmap_size
);
close
(
fd
);
return
false
;
}
close
(
fd
);
mmap_base_
=
map_result
;
mmap_size_
=
mmap_size
;
return
true
;
}
void
PropertyInfoAreaFile
::
Reset
()
{
if
(
mmap_size_
>
0
)
{
munmap
(
mmap_base_
,
mmap_size_
);
}
mmap_base_
=
nullptr
;
mmap_size_
=
0
;
}
}
// namespace properties
}
// namespace android
native/jni/resetprop/libsystemproperties/system_properties.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "system_properties/system_properties.h"
#include <errno.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <new>
#include <async_safe/log.h>
#include "private/ErrnoRestorer.h"
#include "private/bionic_futex.h"
#include "system_properties/context_node.h"
#include "system_properties/prop_area.h"
#include "system_properties/prop_info.h"
#define SERIAL_DIRTY(serial) ((serial)&1)
#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
static
bool
is_dir
(
const
char
*
pathname
)
{
struct
stat
info
;
if
(
stat
(
pathname
,
&
info
)
==
-
1
)
{
return
false
;
}
return
S_ISDIR
(
info
.
st_mode
);
}
bool
SystemProperties
::
Init
(
const
char
*
filename
)
{
// This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
ErrnoRestorer
errno_restorer
;
if
(
initialized_
)
{
contexts_
->
ResetAccess
();
return
true
;
}
if
(
strlen
(
filename
)
>=
PROP_FILENAME_MAX
)
{
return
false
;
}
strcpy
(
property_filename_
,
filename
);
if
(
is_dir
(
property_filename_
))
{
if
(
access
(
"/dev/__properties__/property_info"
,
R_OK
)
==
0
)
{
contexts_
=
new
(
contexts_data_
)
ContextsSerialized
();
if
(
!
contexts_
->
Initialize
(
false
,
property_filename_
,
nullptr
))
{
return
false
;
}
}
else
{
contexts_
=
new
(
contexts_data_
)
ContextsSplit
();
if
(
!
contexts_
->
Initialize
(
false
,
property_filename_
,
nullptr
))
{
return
false
;
}
}
}
else
{
contexts_
=
new
(
contexts_data_
)
ContextsPreSplit
();
if
(
!
contexts_
->
Initialize
(
false
,
property_filename_
,
nullptr
))
{
return
false
;
}
}
initialized_
=
true
;
return
true
;
}
bool
SystemProperties
::
AreaInit
(
const
char
*
filename
,
bool
*
fsetxattr_failed
)
{
if
(
strlen
(
filename
)
>=
PROP_FILENAME_MAX
)
{
return
false
;
}
strcpy
(
property_filename_
,
filename
);
contexts_
=
new
(
contexts_data_
)
ContextsSerialized
();
if
(
!
contexts_
->
Initialize
(
true
,
property_filename_
,
fsetxattr_failed
))
{
return
false
;
}
initialized_
=
true
;
return
true
;
}
uint32_t
SystemProperties
::
AreaSerial
()
{
if
(
!
initialized_
)
{
return
-
1
;
}
prop_area
*
pa
=
contexts_
->
GetSerialPropArea
();
if
(
!
pa
)
{
return
-
1
;
}
// Make sure this read fulfilled before __system_property_serial
return
atomic_load_explicit
(
pa
->
serial
(),
memory_order_acquire
);
}
const
prop_info
*
SystemProperties
::
Find
(
const
char
*
name
)
{
if
(
!
initialized_
)
{
return
nullptr
;
}
prop_area
*
pa
=
contexts_
->
GetPropAreaForName
(
name
);
if
(
!
pa
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"Access denied finding property
\"
%s
\"
"
,
name
);
return
nullptr
;
}
return
pa
->
find
(
name
);
}
static
bool
is_read_only
(
const
char
*
name
)
{
return
strncmp
(
name
,
"ro."
,
3
)
==
0
;
}
int
SystemProperties
::
Read
(
const
prop_info
*
pi
,
char
*
name
,
char
*
value
)
{
while
(
true
)
{
uint32_t
serial
=
Serial
(
pi
);
// acquire semantics
size_t
len
=
SERIAL_VALUE_LEN
(
serial
);
memcpy
(
value
,
pi
->
value
,
len
+
1
);
// TODO: Fix the synchronization scheme here.
// There is no fully supported way to implement this kind
// of synchronization in C++11, since the memcpy races with
// updates to pi, and the data being accessed is not atomic.
// The following fence is unintuitive, but would be the
// correct one if memcpy used memory_order_relaxed atomic accesses.
// In practice it seems unlikely that the generated code would
// would be any different, so this should be OK.
atomic_thread_fence
(
memory_order_acquire
);
if
(
serial
==
load_const_atomic
(
&
(
pi
->
serial
),
memory_order_relaxed
))
{
if
(
name
!=
nullptr
)
{
size_t
namelen
=
strlcpy
(
name
,
pi
->
name
,
PROP_NAME_MAX
);
if
(
namelen
>=
PROP_NAME_MAX
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"The property name length for
\"
%s
\"
is >= %d;"
" please use __system_property_read_callback"
" to read this property. (the name is truncated to
\"
%s
\"
)"
,
pi
->
name
,
PROP_NAME_MAX
-
1
,
name
);
}
}
if
(
is_read_only
(
pi
->
name
)
&&
pi
->
is_long
())
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"The property
\"
%s
\"
has a value with length %zu that is too large for"
" __system_property_get()/__system_property_read(); use"
" __system_property_read_callback() instead."
,
pi
->
name
,
strlen
(
pi
->
long_value
()));
}
return
len
;
}
}
}
void
SystemProperties
::
ReadCallback
(
const
prop_info
*
pi
,
void
(
*
callback
)(
void
*
cookie
,
const
char
*
name
,
const
char
*
value
,
uint32_t
serial
),
void
*
cookie
)
{
// Read only properties don't need to copy the value to a temporary buffer, since it can never
// change.
if
(
is_read_only
(
pi
->
name
))
{
uint32_t
serial
=
Serial
(
pi
);
if
(
pi
->
is_long
())
{
callback
(
cookie
,
pi
->
name
,
pi
->
long_value
(),
serial
);
}
else
{
callback
(
cookie
,
pi
->
name
,
pi
->
value
,
serial
);
}
return
;
}
while
(
true
)
{
uint32_t
serial
=
Serial
(
pi
);
// acquire semantics
size_t
len
=
SERIAL_VALUE_LEN
(
serial
);
char
value_buf
[
len
+
1
];
memcpy
(
value_buf
,
pi
->
value
,
len
);
value_buf
[
len
]
=
'\0'
;
// TODO: see todo in Read function
atomic_thread_fence
(
memory_order_acquire
);
if
(
serial
==
load_const_atomic
(
&
(
pi
->
serial
),
memory_order_relaxed
))
{
callback
(
cookie
,
pi
->
name
,
value_buf
,
serial
);
return
;
}
}
}
int
SystemProperties
::
Get
(
const
char
*
name
,
char
*
value
)
{
const
prop_info
*
pi
=
Find
(
name
);
if
(
pi
!=
nullptr
)
{
return
Read
(
pi
,
nullptr
,
value
);
}
else
{
value
[
0
]
=
0
;
return
0
;
}
}
int
SystemProperties
::
Update
(
prop_info
*
pi
,
const
char
*
value
,
unsigned
int
len
)
{
if
(
len
>=
PROP_VALUE_MAX
)
{
return
-
1
;
}
if
(
!
initialized_
)
{
return
-
1
;
}
prop_area
*
pa
=
contexts_
->
GetSerialPropArea
();
if
(
!
pa
)
{
return
-
1
;
}
uint32_t
serial
=
atomic_load_explicit
(
&
pi
->
serial
,
memory_order_relaxed
);
serial
|=
1
;
atomic_store_explicit
(
&
pi
->
serial
,
serial
,
memory_order_relaxed
);
// The memcpy call here also races. Again pretend it
// used memory_order_relaxed atomics, and use the analogous
// counterintuitive fence.
atomic_thread_fence
(
memory_order_release
);
strlcpy
(
pi
->
value
,
value
,
len
+
1
);
atomic_store_explicit
(
&
pi
->
serial
,
(
len
<<
24
)
|
((
serial
+
1
)
&
0xffffff
),
memory_order_release
);
__futex_wake
(
&
pi
->
serial
,
INT32_MAX
);
atomic_store_explicit
(
pa
->
serial
(),
atomic_load_explicit
(
pa
->
serial
(),
memory_order_relaxed
)
+
1
,
memory_order_release
);
__futex_wake
(
pa
->
serial
(),
INT32_MAX
);
return
0
;
}
int
SystemProperties
::
Add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
)
{
if
(
valuelen
>=
PROP_VALUE_MAX
&&
!
is_read_only
(
name
))
{
return
-
1
;
}
if
(
namelen
<
1
)
{
return
-
1
;
}
if
(
!
initialized_
)
{
return
-
1
;
}
prop_area
*
serial_pa
=
contexts_
->
GetSerialPropArea
();
if
(
serial_pa
==
nullptr
)
{
return
-
1
;
}
prop_area
*
pa
=
contexts_
->
GetPropAreaForName
(
name
);
if
(
!
pa
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"Access denied adding property
\"
%s
\"
"
,
name
);
return
-
1
;
}
bool
ret
=
pa
->
add
(
name
,
namelen
,
value
,
valuelen
);
if
(
!
ret
)
{
return
-
1
;
}
// There is only a single mutator, but we want to make sure that
// updates are visible to a reader waiting for the update.
atomic_store_explicit
(
serial_pa
->
serial
(),
atomic_load_explicit
(
serial_pa
->
serial
(),
memory_order_relaxed
)
+
1
,
memory_order_release
);
__futex_wake
(
serial_pa
->
serial
(),
INT32_MAX
);
return
0
;
}
// Wait for non-locked serial, and retrieve it with acquire semantics.
uint32_t
SystemProperties
::
Serial
(
const
prop_info
*
pi
)
{
uint32_t
serial
=
load_const_atomic
(
&
pi
->
serial
,
memory_order_acquire
);
while
(
SERIAL_DIRTY
(
serial
))
{
__futex_wait
(
const_cast
<
_Atomic
(
uint_least32_t
)
*>
(
&
pi
->
serial
),
serial
,
nullptr
);
serial
=
load_const_atomic
(
&
pi
->
serial
,
memory_order_acquire
);
}
return
serial
;
}
uint32_t
SystemProperties
::
WaitAny
(
uint32_t
old_serial
)
{
uint32_t
new_serial
;
Wait
(
nullptr
,
old_serial
,
&
new_serial
,
nullptr
);
return
new_serial
;
}
bool
SystemProperties
::
Wait
(
const
prop_info
*
pi
,
uint32_t
old_serial
,
uint32_t
*
new_serial_ptr
,
const
timespec
*
relative_timeout
)
{
// Are we waiting on the global serial or a specific serial?
atomic_uint_least32_t
*
serial_ptr
;
if
(
pi
==
nullptr
)
{
if
(
!
initialized_
)
{
return
-
1
;
}
prop_area
*
serial_pa
=
contexts_
->
GetSerialPropArea
();
if
(
serial_pa
==
nullptr
)
{
return
-
1
;
}
serial_ptr
=
serial_pa
->
serial
();
}
else
{
serial_ptr
=
const_cast
<
atomic_uint_least32_t
*>
(
&
pi
->
serial
);
}
uint32_t
new_serial
;
do
{
int
rc
;
if
((
rc
=
__futex_wait
(
serial_ptr
,
old_serial
,
relative_timeout
))
!=
0
&&
rc
==
-
ETIMEDOUT
)
{
return
false
;
}
new_serial
=
load_const_atomic
(
serial_ptr
,
memory_order_acquire
);
}
while
(
new_serial
==
old_serial
);
*
new_serial_ptr
=
new_serial
;
return
true
;
}
const
prop_info
*
SystemProperties
::
FindNth
(
unsigned
n
)
{
struct
find_nth
{
const
uint32_t
sought
;
uint32_t
current
;
const
prop_info
*
result
;
explicit
find_nth
(
uint32_t
n
)
:
sought
(
n
),
current
(
0
),
result
(
nullptr
)
{
}
static
void
fn
(
const
prop_info
*
pi
,
void
*
ptr
)
{
find_nth
*
self
=
reinterpret_cast
<
find_nth
*>
(
ptr
);
if
(
self
->
current
++
==
self
->
sought
)
self
->
result
=
pi
;
}
}
state
(
n
);
Foreach
(
find_nth
::
fn
,
&
state
);
return
state
.
result
;
}
int
SystemProperties
::
Foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
if
(
!
initialized_
)
{
return
-
1
;
}
contexts_
->
ForEach
(
propfn
,
cookie
);
return
0
;
}
native/jni/resetprop/persist_props.c
→
native/jni/resetprop/persist_prop
ertie
s.c
View file @
7a002567
File moved
native/jni/resetprop/private/_system_properties.h
View file @
7a002567
...
@@ -36,6 +36,7 @@
...
@@ -36,6 +36,7 @@
#error you should #include <sys/system_properties.h> instead
#error you should #include <sys/system_properties.h> instead
#endif
#endif
//#include <sys/system_properties.h>
#include "system_properties.h"
#include "system_properties.h"
__BEGIN_DECLS
__BEGIN_DECLS
...
@@ -58,17 +59,17 @@ __BEGIN_DECLS
...
@@ -58,17 +59,17 @@ __BEGIN_DECLS
#define PROP_ERROR_SET_FAILED 0x0024
#define PROP_ERROR_SET_FAILED 0x0024
/*
/*
**
Map the property area from the specified filename. This
**
This was previously for testing, but now that SystemProperties is its own testable class,
**
method is for testing only
.
**
there is never a reason to call this function and its implementation simply returns -1
.
*/
*/
int
__system_property_set_filename
(
const
char
*
filename
);
int
__system_property_set_filename
(
const
char
*
__
filename
);
/*
/*
** Initialize the area to be used to store properties. Can
** Initialize the area to be used to store properties. Can
** only be done by a single process that has write access to
** only be done by a single process that has write access to
** the property area.
** the property area.
*/
*/
int
__system_property_area_init
();
int
__system_property_area_init
(
void
);
/* Read the global serial number of the system properties
/* Read the global serial number of the system properties
**
**
...
@@ -92,7 +93,7 @@ int __system_property_area_init();
...
@@ -92,7 +93,7 @@ int __system_property_area_init();
**
**
** Returns the serial number on success, -1 on error.
** Returns the serial number on success, -1 on error.
*/
*/
uint32_t
__system_property_area_serial
();
uint32_t
__system_property_area_serial
(
void
);
/* Add a new system property. Can only be done by a single
/* Add a new system property. Can only be done by a single
** process that has write access to the property area, and
** process that has write access to the property area, and
...
@@ -102,13 +103,7 @@ uint32_t __system_property_area_serial();
...
@@ -102,13 +103,7 @@ uint32_t __system_property_area_serial();
**
**
** Returns 0 on success, -1 if the property area is full.
** Returns 0 on success, -1 if the property area is full.
*/
*/
int
__system_property_add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
);
int
__system_property_add
(
const
char
*
__name
,
unsigned
int
__name_length
,
const
char
*
__value
,
unsigned
int
__value_length
);
/* Delete a new system property. Added in resetprop
**
** Returns 0 on success, -1 if the property area is full.
*/
int
__system_property_del
(
const
char
*
name
);
/* Update the value of a system property returned by
/* Update the value of a system property returned by
** __system_property_find. Can only be done by a single process
** __system_property_find. Can only be done by a single process
...
@@ -118,14 +113,14 @@ int __system_property_del(const char *name);
...
@@ -118,14 +113,14 @@ int __system_property_del(const char *name);
**
**
** Returns 0 on success, -1 if the parameters are incorrect.
** Returns 0 on success, -1 if the parameters are incorrect.
*/
*/
int
__system_property_update
(
prop_info
*
pi
,
const
char
*
value
,
unsigned
int
len
);
int
__system_property_update
(
prop_info
*
__pi
,
const
char
*
__value
,
unsigned
int
__value_length
);
/* Read the serial number of a system property returned by
/* Read the serial number of a system property returned by
** __system_property_find.
** __system_property_find.
**
**
** Returns the serial number on success, -1 on error.
** Returns the serial number on success, -1 on error.
*/
*/
uint32_t
__system_property_serial
(
const
prop_info
*
pi
);
uint32_t
__system_property_serial
(
const
prop_info
*
__
pi
);
/* Initialize the system properties area in read only mode.
/* Initialize the system properties area in read only mode.
* Should be done by all processes that need to read system
* Should be done by all processes that need to read system
...
@@ -133,10 +128,10 @@ uint32_t __system_property_serial(const prop_info* pi);
...
@@ -133,10 +128,10 @@ uint32_t __system_property_serial(const prop_info* pi);
*
*
* Returns 0 on success, -1 otherwise.
* Returns 0 on success, -1 otherwise.
*/
*/
int
__system_properties_init
();
int
__system_properties_init
(
void
);
/* Deprecated: use __system_property_wait instead. */
/* Deprecated: use __system_property_wait instead. */
uint32_t
__system_property_wait_any
(
uint32_t
old_serial
);
uint32_t
__system_property_wait_any
(
uint32_t
__
old_serial
);
__END_DECLS
__END_DECLS
...
...
native/jni/resetprop/private/bionic_defs.h
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __BIONIC_PRIVATE_BIONIC_DEFS_H_
#define __BIONIC_PRIVATE_BIONIC_DEFS_H_
/*
* This label is used to mark libc/libdl symbols that may need to be replaced
* by native bridge implementation.
*/
#define __BIONIC_WEAK_FOR_NATIVE_BRIDGE __attribute__((__weak__, __noinline__))
#define __BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE __attribute__((__weak__))
#endif
/* __BIONIC_PRIVATE_BIONIC_DEFS_H_ */
native/jni/resetprop/private/bionic_macros.h
View file @
7a002567
...
@@ -40,9 +40,6 @@
...
@@ -40,9 +40,6 @@
TypeName() = delete; \
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
DISALLOW_COPY_AND_ASSIGN(TypeName)
#define BIONIC_ALIGN(value, alignment) \
(((value) + (alignment) - 1) & ~((alignment) - 1))
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
((sizeof(value) == 8) \
((sizeof(value) == 8) \
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
...
@@ -66,4 +63,43 @@ static inline T* align_up(T* p, size_t align) {
...
@@ -66,4 +63,43 @@ static inline T* align_up(T* p, size_t align) {
return
reinterpret_cast
<
T
*>
(
align_up
(
reinterpret_cast
<
uintptr_t
>
(
p
),
align
));
return
reinterpret_cast
<
T
*>
(
align_up
(
reinterpret_cast
<
uintptr_t
>
(
p
),
align
));
}
}
#if defined(__arm__)
// Do not emit anything for arm, clang does not allow emiting an arm unwind
// directive.
// #define BIONIC_STOP_UNWIND asm volatile(".cantunwind")
#define BIONIC_STOP_UNWIND
#elif defined(__aarch64__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined x30")
#elif defined(__i386__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined \%eip")
#elif defined(__x86_64__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined \%rip")
#elif defined (__mips__)
#define BIONIC_STOP_UNWIND asm volatile(".cfi_undefined $ra")
#endif
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// One caveat is that arraysize() doesn't accept any array of an
// anonymous type or a type defined inside a function.
//
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template
<
typename
T
,
size_t
N
>
char
(
&
ArraySizeHelper
(
T
(
&
array
)[
N
]))[
N
];
// NOLINT(readability/casting)
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// Used to inform clang's -Wimplicit-fallthrough that a fallthrough is intended. There's no way to
// silence (or enable, apparently) -Wimplicit-fallthrough in C yet.
#ifdef __cplusplus
#define __BIONIC_FALLTHROUGH [[clang::fallthrough]]
#else
#define __BIONIC_FALLTHROUGH
#endif
#endif // _BIONIC_MACROS_H_
#endif // _BIONIC_MACROS_H_
native/jni/resetprop/private/futex.h
deleted
100644 → 0
View file @
ad7ec799
/****************************************************************************
****************************************************************************
***
*** This header was automatically generated from a Linux kernel header
*** of the same name, to make information necessary for userspace to
*** call into the kernel available to libc. It contains only constants,
*** structures, and macros generated from the original header, and thus,
*** contains no copyrightable information.
***
*** To edit the content of this header, modify the corresponding
*** source file (e.g. under external/kernel-headers/original/) then
*** run bionic/libc/kernel/tools/update_all.py
***
*** Any manual change here will be lost the next time this script will
*** be run. You've been warned!
***
****************************************************************************
****************************************************************************/
#ifndef _UAPI_LINUX_FUTEX_H
#define _UAPI_LINUX_FUTEX_H
#include <linux/compiler.h>
#include <linux/types.h>
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_FD 2
#define FUTEX_REQUEUE 3
#define FUTEX_CMP_REQUEUE 4
#define FUTEX_WAKE_OP 5
#define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8
#define FUTEX_WAIT_BITSET 9
#define FUTEX_WAKE_BITSET 10
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | FUTEX_PRIVATE_FLAG)
struct
robust_list
{
struct
robust_list
__user
*
next
;
};
struct
robust_list_head
{
struct
robust_list
list
;
long
futex_offset
;
struct
robust_list
__user
*
list_op_pending
;
};
#define FUTEX_WAITERS 0x80000000
#define FUTEX_OWNER_DIED 0x40000000
#define FUTEX_TID_MASK 0x3fffffff
#define ROBUST_LIST_LIMIT 2048
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
#define FUTEX_OP_SET 0
#define FUTEX_OP_ADD 1
#define FUTEX_OP_OR 2
#define FUTEX_OP_ANDN 3
#define FUTEX_OP_XOR 4
#define FUTEX_OP_OPARG_SHIFT 8
#define FUTEX_OP_CMP_EQ 0
#define FUTEX_OP_CMP_NE 1
#define FUTEX_OP_CMP_LT 2
#define FUTEX_OP_CMP_LE 3
#define FUTEX_OP_CMP_GT 4
#define FUTEX_OP_CMP_GE 5
#define FUTEX_OP(op,oparg,cmp,cmparg) (((op & 0xf) << 28) | ((cmp & 0xf) << 24) | ((oparg & 0xfff) << 12) | (cmparg & 0xfff))
#endif
native/jni/resetprop/private/redefs.h
View file @
7a002567
...
@@ -17,5 +17,6 @@
...
@@ -17,5 +17,6 @@
#define __system_property_serial __system_property_serial2
#define __system_property_serial __system_property_serial2
#define __system_properties_init __system_properties_init2
#define __system_properties_init __system_properties_init2
#define __system_property_wait_any __system_property_wait_any2
#define __system_property_wait_any __system_property_wait_any2
#define __system_property_del(x) -1
/* Temp disable */
#endif //REDEFS_H
#endif //REDEFS_H
native/jni/resetprop/private/stdatomic.h
deleted
100644 → 0
View file @
ad7ec799
/*
* An implementation of C11 stdatomic.h directly borrowed from FreeBSD
* (original copyright follows), with minor modifications for
* portability to other systems. Works for recent Clang (that
* implement the feature c_atomic) and GCC 4.7+; includes
* compatibility for GCC below 4.7 but I wouldn't recommend it.
*
* Caveats and limitations:
* - Only the ``_Atomic parentheses'' notation is implemented, while
* the ``_Atomic space'' one is not.
* - _Atomic types must be typedef'ed, or programs using them will
* not type check correctly (incompatible anonymous structure
* types).
* - Non-scalar _Atomic types would require runtime support for
* runtime locking, which, as far as I know, is not currently
* available on any system.
*/
/*-
* Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
* David Chisnall <theraven@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/include/stdatomic.h,v 1.10.2.2 2012/05/30 19:21:54 theraven Exp $
*/
#ifndef _STDATOMIC_H_
#define _STDATOMIC_H_
#include <stddef.h>
#include <stdint.h>
#define _Bool bool
#if !defined(__has_feature)
#define __has_feature(x) 0
#endif
#if !defined(__has_builtin)
#define __has_builtin(x) 0
#endif
#if !defined(__GNUC_PREREQ__)
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define __GNUC_PREREQ__(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
#define __GNUC_PREREQ__(maj, min) 0
#endif
#endif
#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS)
#if __has_feature(c_atomic)
#define __CLANG_ATOMICS
#elif __GNUC_PREREQ__(4, 7)
#define __GNUC_ATOMICS
#elif !defined(__GNUC__)
#error "stdatomic.h does not support your compiler"
#endif
#endif
#if !defined(__CLANG_ATOMICS)
#define _Atomic(T) struct { volatile __typeof__(T) __val; }
#endif
/*
* 7.17.2 Initialization.
*/
#if defined(__CLANG_ATOMICS)
#define ATOMIC_VAR_INIT(value) (value)
#define atomic_init(obj, value) __c11_atomic_init(obj, value)
#else
#define ATOMIC_VAR_INIT(value) { .__val = (value) }
#define atomic_init(obj, value) do { \
(obj)->__val = (value); \
} while (0)
#endif
/*
* Clang and recent GCC both provide predefined macros for the memory
* orderings. If we are using a compiler that doesn't define them, use the
* clang values - these will be ignored in the fallback path.
*/
#ifndef __ATOMIC_RELAXED
#define __ATOMIC_RELAXED 0
#endif
#ifndef __ATOMIC_CONSUME
#define __ATOMIC_CONSUME 1
#endif
#ifndef __ATOMIC_ACQUIRE
#define __ATOMIC_ACQUIRE 2
#endif
#ifndef __ATOMIC_RELEASE
#define __ATOMIC_RELEASE 3
#endif
#ifndef __ATOMIC_ACQ_REL
#define __ATOMIC_ACQ_REL 4
#endif
#ifndef __ATOMIC_SEQ_CST
#define __ATOMIC_SEQ_CST 5
#endif
/*
* 7.17.3 Order and consistency.
*
* The memory_order_* constants that denote the barrier behaviour of the
* atomic operations.
*/
enum
memory_order
{
memory_order_relaxed
=
__ATOMIC_RELAXED
,
memory_order_consume
=
__ATOMIC_CONSUME
,
memory_order_acquire
=
__ATOMIC_ACQUIRE
,
memory_order_release
=
__ATOMIC_RELEASE
,
memory_order_acq_rel
=
__ATOMIC_ACQ_REL
,
memory_order_seq_cst
=
__ATOMIC_SEQ_CST
};
typedef
enum
memory_order
memory_order
;
/*
* 7.17.4 Fences.
*/
#ifdef __CLANG_ATOMICS
#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
#elif defined(__GNUC_ATOMICS)
#define atomic_thread_fence(order) __atomic_thread_fence(order)
#define atomic_signal_fence(order) __atomic_signal_fence(order)
#else
#define atomic_thread_fence(order) __sync_synchronize()
#define atomic_signal_fence(order) __asm volatile ("" : : : "memory")
#endif
/*
* 7.17.5 Lock-free property.
*/
#if defined(__CLANG_ATOMICS)
#define atomic_is_lock_free(obj) \
__c11_atomic_is_lock_free(sizeof(obj))
#elif defined(__GNUC_ATOMICS)
#define atomic_is_lock_free(obj) \
__atomic_is_lock_free(sizeof((obj)->__val))
#else
#define atomic_is_lock_free(obj) \
(sizeof((obj)->__val) <= sizeof(void *))
#endif
/*
* 7.17.6 Atomic integer types.
*/
typedef
_Atomic
(
_Bool
)
atomic_bool
;
typedef
_Atomic
(
char
)
atomic_char
;
typedef
_Atomic
(
signed
char
)
atomic_schar
;
typedef
_Atomic
(
unsigned
char
)
atomic_uchar
;
typedef
_Atomic
(
short
)
atomic_short
;
typedef
_Atomic
(
unsigned
short
)
atomic_ushort
;
typedef
_Atomic
(
int
)
atomic_int
;
typedef
_Atomic
(
unsigned
int
)
atomic_uint
;
typedef
_Atomic
(
long
)
atomic_long
;
typedef
_Atomic
(
unsigned
long
)
atomic_ulong
;
typedef
_Atomic
(
long
long
)
atomic_llong
;
typedef
_Atomic
(
unsigned
long
long
)
atomic_ullong
;
#if 0
typedef _Atomic(char16_t) atomic_char16_t;
typedef _Atomic(char32_t) atomic_char32_t;
#endif
typedef
_Atomic
(
wchar_t
)
atomic_wchar_t
;
typedef
_Atomic
(
int_least8_t
)
atomic_int_least8_t
;
typedef
_Atomic
(
uint_least8_t
)
atomic_uint_least8_t
;
typedef
_Atomic
(
int_least16_t
)
atomic_int_least16_t
;
typedef
_Atomic
(
uint_least16_t
)
atomic_uint_least16_t
;
typedef
_Atomic
(
int_least32_t
)
atomic_int_least32_t
;
typedef
_Atomic
(
uint_least32_t
)
atomic_uint_least32_t
;
typedef
_Atomic
(
int_least64_t
)
atomic_int_least64_t
;
typedef
_Atomic
(
uint_least64_t
)
atomic_uint_least64_t
;
typedef
_Atomic
(
int_fast8_t
)
atomic_int_fast8_t
;
typedef
_Atomic
(
uint_fast8_t
)
atomic_uint_fast8_t
;
typedef
_Atomic
(
int_fast16_t
)
atomic_int_fast16_t
;
typedef
_Atomic
(
uint_fast16_t
)
atomic_uint_fast16_t
;
typedef
_Atomic
(
int_fast32_t
)
atomic_int_fast32_t
;
typedef
_Atomic
(
uint_fast32_t
)
atomic_uint_fast32_t
;
typedef
_Atomic
(
int_fast64_t
)
atomic_int_fast64_t
;
typedef
_Atomic
(
uint_fast64_t
)
atomic_uint_fast64_t
;
typedef
_Atomic
(
intptr_t
)
atomic_intptr_t
;
typedef
_Atomic
(
uintptr_t
)
atomic_uintptr_t
;
typedef
_Atomic
(
size_t
)
atomic_size_t
;
typedef
_Atomic
(
ptrdiff_t
)
atomic_ptrdiff_t
;
typedef
_Atomic
(
intmax_t
)
atomic_intmax_t
;
typedef
_Atomic
(
uintmax_t
)
atomic_uintmax_t
;
/*
* 7.17.7 Operations on atomic types.
*/
/*
* Compiler-specific operations.
*/
#if defined(__CLANG_ATOMICS)
#define atomic_compare_exchange_strong_explicit(object, expected, \
desired, success, failure) \
__c11_atomic_compare_exchange_strong(object, expected, desired, \
success, failure)
#define atomic_compare_exchange_weak_explicit(object, expected, \
desired, success, failure) \
__c11_atomic_compare_exchange_weak(object, expected, desired, \
success, failure)
#define atomic_exchange_explicit(object, desired, order) \
__c11_atomic_exchange(object, desired, order)
#define atomic_fetch_add_explicit(object, operand, order) \
__c11_atomic_fetch_add(object, operand, order)
#define atomic_fetch_and_explicit(object, operand, order) \
__c11_atomic_fetch_and(object, operand, order)
#define atomic_fetch_or_explicit(object, operand, order) \
__c11_atomic_fetch_or(object, operand, order)
#define atomic_fetch_sub_explicit(object, operand, order) \
__c11_atomic_fetch_sub(object, operand, order)
#define atomic_fetch_xor_explicit(object, operand, order) \
__c11_atomic_fetch_xor(object, operand, order)
#define atomic_load_explicit(object, order) \
__c11_atomic_load(object, order)
#define atomic_store_explicit(object, desired, order) \
__c11_atomic_store(object, desired, order)
#elif defined(__GNUC_ATOMICS)
#define atomic_compare_exchange_strong_explicit(object, expected, \
desired, success, failure) \
__atomic_compare_exchange_n(&(object)->__val, expected, \
desired, 0, success, failure)
#define atomic_compare_exchange_weak_explicit(object, expected, \
desired, success, failure) \
__atomic_compare_exchange_n(&(object)->__val, expected, \
desired, 1, success, failure)
#define atomic_exchange_explicit(object, desired, order) \
__atomic_exchange_n(&(object)->__val, desired, order)
#define atomic_fetch_add_explicit(object, operand, order) \
__atomic_fetch_add(&(object)->__val, operand, order)
#define atomic_fetch_and_explicit(object, operand, order) \
__atomic_fetch_and(&(object)->__val, operand, order)
#define atomic_fetch_or_explicit(object, operand, order) \
__atomic_fetch_or(&(object)->__val, operand, order)
#define atomic_fetch_sub_explicit(object, operand, order) \
__atomic_fetch_sub(&(object)->__val, operand, order)
#define atomic_fetch_xor_explicit(object, operand, order) \
__atomic_fetch_xor(&(object)->__val, operand, order)
#define atomic_load_explicit(object, order) \
__atomic_load_n(&(object)->__val, order)
#define atomic_store_explicit(object, desired, order) \
__atomic_store_n(&(object)->__val, desired, order)
#else
#define atomic_compare_exchange_strong_explicit(object, expected, \
desired, success, failure) ({ \
__typeof__((object)->__val) __v; \
_Bool __r; \
__v = __sync_val_compare_and_swap(&(object)->__val, \
*(expected), desired); \
__r = *(expected) == __v; \
*(expected) = __v; \
__r; \
})
#define atomic_compare_exchange_weak_explicit(object, expected, \
desired, success, failure) \
atomic_compare_exchange_strong_explicit(object, expected, \
desired, success, failure)
#if __has_builtin(__sync_swap)
/* Clang provides a full-barrier atomic exchange - use it if available. */
#define atomic_exchange_explicit(object, desired, order) \
__sync_swap(&(object)->__val, desired)
#else
/*
* __sync_lock_test_and_set() is only an acquire barrier in theory (although in
* practice it is usually a full barrier) so we need an explicit barrier after
* it.
*/
#define atomic_exchange_explicit(object, desired, order) ({ \
__typeof__((object)->__val) __v; \
__v = __sync_lock_test_and_set(&(object)->__val, desired); \
__sync_synchronize(); \
__v; \
})
#endif
#define atomic_fetch_add_explicit(object, operand, order) \
__sync_fetch_and_add(&(object)->__val, operand)
#define atomic_fetch_and_explicit(object, operand, order) \
__sync_fetch_and_and(&(object)->__val, operand)
#define atomic_fetch_or_explicit(object, operand, order) \
__sync_fetch_and_or(&(object)->__val, operand)
#define atomic_fetch_sub_explicit(object, operand, order) \
__sync_fetch_and_sub(&(object)->__val, operand)
#define atomic_fetch_xor_explicit(object, operand, order) \
__sync_fetch_and_xor(&(object)->__val, operand)
#define atomic_load_explicit(object, order) \
__sync_fetch_and_add(&(object)->__val, 0)
#define atomic_store_explicit(object, desired, order) do { \
__sync_synchronize(); \
(object)->__val = (desired); \
__sync_synchronize(); \
} while (0)
#endif
/*
* Convenience functions.
*/
#define atomic_compare_exchange_strong(object, expected, desired) \
atomic_compare_exchange_strong_explicit(object, expected, \
desired, memory_order_seq_cst, memory_order_seq_cst)
#define atomic_compare_exchange_weak(object, expected, desired) \
atomic_compare_exchange_weak_explicit(object, expected, \
desired, memory_order_seq_cst, memory_order_seq_cst)
#define atomic_exchange(object, desired) \
atomic_exchange_explicit(object, desired, memory_order_seq_cst)
#define atomic_fetch_add(object, operand) \
atomic_fetch_add_explicit(object, operand, memory_order_seq_cst)
#define atomic_fetch_and(object, operand) \
atomic_fetch_and_explicit(object, operand, memory_order_seq_cst)
#define atomic_fetch_or(object, operand) \
atomic_fetch_or_explicit(object, operand, memory_order_seq_cst)
#define atomic_fetch_sub(object, operand) \
atomic_fetch_sub_explicit(object, operand, memory_order_seq_cst)
#define atomic_fetch_xor(object, operand) \
atomic_fetch_xor_explicit(object, operand, memory_order_seq_cst)
#define atomic_load(object) \
atomic_load_explicit(object, memory_order_seq_cst)
#define atomic_store(object, desired) \
atomic_store_explicit(object, desired, memory_order_seq_cst)
/*
* 7.17.8 Atomic flag type and operations.
*/
typedef
atomic_bool
atomic_flag
;
#define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
#define atomic_flag_clear_explicit(object, order) \
atomic_store_explicit(object, 0, order)
#define atomic_flag_test_and_set_explicit(object, order) \
atomic_compare_exchange_strong_explicit(object, 0, 1, order, order)
#define atomic_flag_clear(object) \
atomic_flag_clear_explicit(object, memory_order_seq_cst)
#define atomic_flag_test_and_set(object) \
atomic_flag_test_and_set_explicit(object, memory_order_seq_cst)
#endif
/* !_STDATOMIC_H_ */
\ No newline at end of file
native/jni/resetprop/private/system_properties.h
View file @
7a002567
...
@@ -33,7 +33,6 @@
...
@@ -33,7 +33,6 @@
#include <stdbool.h>
#include <stdbool.h>
#include <stddef.h>
#include <stddef.h>
#include <stdint.h>
#include <stdint.h>
#include "redefs.h"
#include "redefs.h"
__BEGIN_DECLS
__BEGIN_DECLS
...
@@ -43,9 +42,9 @@ typedef struct prop_info prop_info;
...
@@ -43,9 +42,9 @@ typedef struct prop_info prop_info;
#define PROP_VALUE_MAX 92
#define PROP_VALUE_MAX 92
/*
/*
* Sets system property `
key
` to `value`, creating the system property if it doesn't already exist.
* Sets system property `
name
` to `value`, creating the system property if it doesn't already exist.
*/
*/
int
__system_property_set
(
const
char
*
key
,
const
char
*
value
);
int
__system_property_set
(
const
char
*
__name
,
const
char
*
__value
)
__INTRODUCED_IN
(
12
);
/*
/*
* Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist.
* Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist.
...
@@ -53,14 +52,14 @@ int __system_property_set(const char *key, const char *value);
...
@@ -53,14 +52,14 @@ int __system_property_set(const char *key, const char *value);
*
*
* Property lookup is expensive, so it can be useful to cache the result of this function.
* Property lookup is expensive, so it can be useful to cache the result of this function.
*/
*/
const
prop_info
*
__system_property_find
(
const
char
*
name
);
const
prop_info
*
__system_property_find
(
const
char
*
__
name
);
/*
/*
* Calls `callback` with a consistent trio of name, value, and serial number for property `pi`.
* Calls `callback` with a consistent trio of name, value, and serial number for property `pi`.
*/
*/
void
__system_property_read_callback
(
const
prop_info
*
pi
,
void
__system_property_read_callback
(
const
prop_info
*
__
pi
,
void
(
*
callback
)(
void
*
cookie
,
const
char
*
name
,
const
char
*
value
,
uint32_t
serial
),
void
(
*
__callback
)(
void
*
__cookie
,
const
char
*
__name
,
const
char
*
__value
,
uint32_t
__
serial
),
void
*
cookie
);
void
*
__cookie
)
__INTRODUCED_IN
(
26
);
/*
/*
* Passes a `prop_info` for each system property to the provided
* Passes a `prop_info` for each system property to the provided
...
@@ -68,7 +67,8 @@ void __system_property_read_callback(const prop_info *pi,
...
@@ -68,7 +67,8 @@ void __system_property_read_callback(const prop_info *pi,
*
*
* This method is for inspecting and debugging the property system, and not generally useful.
* This method is for inspecting and debugging the property system, and not generally useful.
*/
*/
int
__system_property_foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
);
int
__system_property_foreach
(
void
(
*
__callback
)(
const
prop_info
*
__pi
,
void
*
__cookie
),
void
*
__cookie
)
__INTRODUCED_IN
(
19
);
/*
/*
* Waits for the specific system property identified by `pi` to be updated
* Waits for the specific system property identified by `pi` to be updated
...
@@ -83,19 +83,17 @@ int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
...
@@ -83,19 +83,17 @@ int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
* timed out.
* timed out.
*/
*/
struct
timespec
;
struct
timespec
;
bool
__system_property_wait
(
const
prop_info
*
pi
,
bool
__system_property_wait
(
const
prop_info
*
__pi
,
uint32_t
__old_serial
,
uint32_t
*
__new_serial_ptr
,
const
struct
timespec
*
__relative_timeout
)
uint32_t
old_serial
,
__INTRODUCED_IN
(
26
);
uint32_t
*
new_serial_ptr
,
const
struct
timespec
*
relative_timeout
);
/* Deprecated. In Android O and above, there's no limit on property name length. */
/* Deprecated. In Android O and above, there's no limit on property name length. */
#define PROP_NAME_MAX 32
#define PROP_NAME_MAX 32
/* Deprecated. Use __system_property_read_callback instead. */
/* Deprecated. Use __system_property_read_callback instead. */
int
__system_property_read
(
const
prop_info
*
pi
,
char
*
name
,
char
*
value
);
int
__system_property_read
(
const
prop_info
*
__pi
,
char
*
__name
,
char
*
__
value
);
/* Deprecated. Use __system_property_read_callback instead. */
/* Deprecated. Use __system_property_read_callback instead. */
int
__system_property_get
(
const
char
*
name
,
char
*
value
);
int
__system_property_get
(
const
char
*
__name
,
char
*
__
value
);
/* Deprecated. Use __system_property_foreach instead. */
/* Deprecated. Use __system_property_foreach instead. */
const
prop_info
*
__system_property_find_nth
(
unsigned
n
);
const
prop_info
*
__system_property_find_nth
(
unsigned
__
n
);
__END_DECLS
__END_DECLS
...
...
native/jni/resetprop/private/xattr.h
deleted
100644 → 0
View file @
ad7ec799
/****************************************************************************
****************************************************************************
***
*** This header was automatically generated from a Linux kernel header
*** of the same name, to make information necessary for userspace to
*** call into the kernel available to libc. It contains only constants,
*** structures, and macros generated from the original header, and thus,
*** contains no copyrightable information.
***
*** To edit the content of this header, modify the corresponding
*** source file (e.g. under external/kernel-headers/original/) then
*** run bionic/libc/kernel/tools/update_all.py
***
*** Any manual change here will be lost the next time this script will
*** be run. You've been warned!
***
****************************************************************************
****************************************************************************/
#ifndef _UAPI_LINUX_XATTR_H
#define _UAPI_LINUX_XATTR_H
#define XATTR_OS2_PREFIX "os2."
#define XATTR_OS2_PREFIX_LEN (sizeof(XATTR_OS2_PREFIX) - 1)
#define XATTR_MAC_OSX_PREFIX "osx."
#define XATTR_MAC_OSX_PREFIX_LEN (sizeof(XATTR_MAC_OSX_PREFIX) - 1)
#define XATTR_BTRFS_PREFIX "btrfs."
#define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1)
#define XATTR_SECURITY_PREFIX "security."
#define XATTR_SECURITY_PREFIX_LEN (sizeof(XATTR_SECURITY_PREFIX) - 1)
#define XATTR_SYSTEM_PREFIX "system."
#define XATTR_SYSTEM_PREFIX_LEN (sizeof(XATTR_SYSTEM_PREFIX) - 1)
#define XATTR_TRUSTED_PREFIX "trusted."
#define XATTR_TRUSTED_PREFIX_LEN (sizeof(XATTR_TRUSTED_PREFIX) - 1)
#define XATTR_USER_PREFIX "user."
#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1)
#define XATTR_EVM_SUFFIX "evm"
#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX
#define XATTR_IMA_SUFFIX "ima"
#define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
#define XATTR_SMACK_SUFFIX "SMACK64"
#define XATTR_SMACK_IPIN "SMACK64IPIN"
#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
#define XATTR_SMACK_EXEC "SMACK64EXEC"
#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE"
#define XATTR_SMACK_MMAP "SMACK64MMAP"
#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC
#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
#define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP
#define XATTR_APPARMOR_SUFFIX "apparmor"
#define XATTR_NAME_APPARMOR XATTR_SECURITY_PREFIX XATTR_APPARMOR_SUFFIX
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
#define XATTR_POSIX_ACL_ACCESS "posix_acl_access"
#define XATTR_NAME_POSIX_ACL_ACCESS XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_ACCESS
#define XATTR_POSIX_ACL_DEFAULT "posix_acl_default"
#define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
#endif
native/jni/resetprop/system_properties.cpp
deleted
100644 → 0
View file @
ad7ec799
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define typeof __typeof__
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include "private/stdatomic.h"
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <new>
#include "private/xattr.h"
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
//#include <sys/xattr.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include "private/_system_properties.h"
#include "private/system_properties.h"
// #include <async_safe/log.h>
// #include "private/ErrnoRestorer.h"
#include "private/bionic_futex.h"
#include "private/bionic_lock.h"
#include "private/bionic_macros.h"
// #include "private/bionic_sdk_version.h"
/***************
* Workarounds *
***************/
#define async_safe_format_buffer snprintf
#define async_safe_format_log(...)
/* NOP */
#define CHECK(...)
/* NOP */
#define getline my_getline
static
int
fsetxattr
(
int
fd
,
const
char
*
name
,
const
void
*
value
,
size_t
size
,
int
flags
)
{
return
(
int
)
syscall
(
__NR_fsetxattr
,
fd
,
name
,
value
,
size
,
flags
);
}
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC O_CLOEXEC
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
extern
"C"
ssize_t
my_getline
(
char
**
,
size_t
*
,
FILE
*
);
/******************
* Workaround End *
******************/
static
constexpr
int
PROP_FILENAME_MAX
=
1024
;
static
constexpr
uint32_t
PROP_AREA_MAGIC
=
0x504f5250
;
static
constexpr
uint32_t
PROP_AREA_VERSION
=
0xfc6ed0ab
;
static
constexpr
size_t
PA_SIZE
=
128
*
1024
;
#define SERIAL_DIRTY(serial) ((serial)&1)
#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
static
const
char
property_service_socket
[]
=
"/dev/socket/"
PROP_SERVICE_NAME
;
static
const
char
*
kServiceVersionPropertyName
=
"ro.property_service.version"
;
/*
* Properties are stored in a hybrid trie/binary tree structure.
* Each property's name is delimited at '.' characters, and the tokens are put
* into a trie structure. Siblings at each level of the trie are stored in a
* binary tree. For instance, "ro.secure"="1" could be stored as follows:
*
* +-----+ children +----+ children +--------+
* | |-------------->| ro |-------------->| secure |
* +-----+ +----+ +--------+
* / \ / |
* left / \ right left / | prop +===========+
* v v v +-------->| ro.secure |
* +-----+ +-----+ +-----+ +-----------+
* | net | | sys | | com | | 1 |
* +-----+ +-----+ +-----+ +===========+
*/
// Represents a node in the trie.
struct
prop_bt
{
uint32_t
namelen
;
// The property trie is updated only by the init process (single threaded) which provides
// property service. And it can be read by multiple threads at the same time.
// As the property trie is not protected by locks, we use atomic_uint_least32_t types for the
// left, right, children "pointers" in the trie node. To make sure readers who see the
// change of "pointers" can also notice the change of prop_bt structure contents pointed by
// the "pointers", we always use release-consume ordering pair when accessing these "pointers".
// prop "points" to prop_info structure if there is a propery associated with the trie node.
// Its situation is similar to the left, right, children "pointers". So we use
// atomic_uint_least32_t and release-consume ordering to protect it as well.
// We should also avoid rereading these fields redundantly, since not
// all processor implementations ensure that multiple loads from the
// same field are carried out in the right order.
atomic_uint_least32_t
prop
;
atomic_uint_least32_t
left
;
atomic_uint_least32_t
right
;
atomic_uint_least32_t
children
;
char
name
[
0
];
prop_bt
(
const
char
*
name
,
const
uint32_t
name_length
)
{
this
->
namelen
=
name_length
;
memcpy
(
this
->
name
,
name
,
name_length
);
this
->
name
[
name_length
]
=
'\0'
;
}
private
:
DISALLOW_COPY_AND_ASSIGN
(
prop_bt
);
};
class
prop_area
{
public
:
prop_area
(
const
uint32_t
magic
,
const
uint32_t
version
)
:
magic_
(
magic
),
version_
(
version
)
{
atomic_init
(
&
serial_
,
0
);
memset
(
reserved_
,
0
,
sizeof
(
reserved_
));
// Allocate enough space for the root node.
bytes_used_
=
sizeof
(
prop_bt
);
}
const
prop_info
*
find
(
const
char
*
name
);
bool
del
(
const
char
*
name
);
/* resetprop add */
bool
add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
);
bool
foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
);
atomic_uint_least32_t
*
serial
()
{
return
&
serial_
;
}
uint32_t
magic
()
const
{
return
magic_
;
}
uint32_t
version
()
const
{
return
version_
;
}
private
:
void
*
allocate_obj
(
const
size_t
size
,
uint_least32_t
*
const
off
);
prop_bt
*
new_prop_bt
(
const
char
*
name
,
uint32_t
namelen
,
uint_least32_t
*
const
off
);
prop_info
*
new_prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
uint_least32_t
*
const
off
);
void
*
to_prop_obj
(
uint_least32_t
off
);
prop_bt
*
to_prop_bt
(
atomic_uint_least32_t
*
off_p
);
prop_info
*
to_prop_info
(
atomic_uint_least32_t
*
off_p
);
prop_bt
*
root_node
();
prop_bt
*
find_prop_bt
(
prop_bt
*
const
bt
,
const
char
*
name
,
uint32_t
namelen
,
bool
alloc_if_needed
);
const
prop_info
*
find_property
(
prop_bt
*
const
trie
,
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
bool
alloc_if_needed
);
bool
find_property_and_del
(
prop_bt
*
const
trie
,
const
char
*
name
);
/* resetprop add */
bool
foreach_property
(
prop_bt
*
const
trie
,
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
);
uint32_t
bytes_used_
;
atomic_uint_least32_t
serial_
;
uint32_t
magic_
;
uint32_t
version_
;
uint32_t
reserved_
[
28
];
char
data_
[
0
];
DISALLOW_COPY_AND_ASSIGN
(
prop_area
);
};
struct
prop_info
{
atomic_uint_least32_t
serial
;
// we need to keep this buffer around because the property
// value can be modified whereas name is constant.
char
value
[
PROP_VALUE_MAX
];
char
name
[
0
];
prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
)
{
memcpy
(
this
->
name
,
name
,
namelen
);
this
->
name
[
namelen
]
=
'\0'
;
atomic_init
(
&
this
->
serial
,
valuelen
<<
24
);
memcpy
(
this
->
value
,
value
,
valuelen
);
this
->
value
[
valuelen
]
=
'\0'
;
}
private
:
DISALLOW_IMPLICIT_CONSTRUCTORS
(
prop_info
);
};
// This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol.
// Change to static, we don't want to use the global libc reference
static
prop_area
*
__system_property_area__
=
nullptr
;
static
char
property_filename
[
PROP_FILENAME_MAX
]
=
PROP_FILENAME
;
static
size_t
pa_data_size
;
static
size_t
pa_size
;
static
bool
initialized
=
false
;
static
prop_area
*
map_prop_area_rw
(
const
char
*
filename
,
const
char
*
context
,
bool
*
fsetxattr_failed
)
{
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
const
int
fd
=
open
(
filename
,
O_RDWR
|
O_CREAT
|
O_NOFOLLOW
|
O_CLOEXEC
|
O_EXCL
,
0444
);
if
(
fd
<
0
)
{
if
(
errno
==
EACCES
)
{
/* for consistency with the case where the process has already
* mapped the page in and segfaults when trying to write to it
*/
abort
();
}
return
nullptr
;
}
if
(
context
)
{
if
(
fsetxattr
(
fd
,
XATTR_NAME_SELINUX
,
context
,
strlen
(
context
)
+
1
,
0
)
!=
0
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"fsetxattr failed to set context (%s) for
\"
%s
\"
"
,
context
,
filename
);
/*
* fsetxattr() will fail during system properties tests due to selinux policy.
* We do not want to create a custom policy for the tester, so we will continue in
* this function but set a flag that an error has occurred.
* Init, which is the only daemon that should ever call this function will abort
* when this error occurs.
* Otherwise, the tester will ignore it and continue, albeit without any selinux
* property separation.
*/
if
(
fsetxattr_failed
)
{
*
fsetxattr_failed
=
true
;
}
}
}
if
(
ftruncate
(
fd
,
PA_SIZE
)
<
0
)
{
close
(
fd
);
return
nullptr
;
}
pa_size
=
PA_SIZE
;
pa_data_size
=
pa_size
-
sizeof
(
prop_area
);
void
*
const
memory_area
=
mmap
(
nullptr
,
pa_size
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
if
(
memory_area
==
MAP_FAILED
)
{
close
(
fd
);
return
nullptr
;
}
prop_area
*
pa
=
new
(
memory_area
)
prop_area
(
PROP_AREA_MAGIC
,
PROP_AREA_VERSION
);
close
(
fd
);
return
pa
;
}
// resetprop: map the memory as rw
static
prop_area
*
map_fd_rw
(
const
int
fd
)
{
struct
stat
fd_stat
;
if
(
fstat
(
fd
,
&
fd_stat
)
<
0
)
{
return
nullptr
;
}
if
((
fd_stat
.
st_uid
!=
0
)
||
(
fd_stat
.
st_gid
!=
0
)
||
((
fd_stat
.
st_mode
&
(
S_IWGRP
|
S_IWOTH
))
!=
0
)
||
(
fd_stat
.
st_size
<
static_cast
<
off_t
>
(
sizeof
(
prop_area
))))
{
return
nullptr
;
}
pa_size
=
fd_stat
.
st_size
;
pa_data_size
=
pa_size
-
sizeof
(
prop_area
);
void
*
const
map_result
=
mmap
(
nullptr
,
pa_size
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
/* resetprop: add PROT_WRITE */
if
(
map_result
==
MAP_FAILED
)
{
return
nullptr
;
}
prop_area
*
pa
=
reinterpret_cast
<
prop_area
*>
(
map_result
);
if
((
pa
->
magic
()
!=
PROP_AREA_MAGIC
)
||
(
pa
->
version
()
!=
PROP_AREA_VERSION
))
{
munmap
(
pa
,
pa_size
);
return
nullptr
;
}
return
pa
;
}
static
prop_area
*
map_prop_area
(
const
char
*
filename
)
{
int
fd
=
open
(
filename
,
O_CLOEXEC
|
O_NOFOLLOW
|
O_RDWR
);
/* resetprop: O_RDONLY -> O_RDWR */
if
(
fd
==
-
1
)
return
nullptr
;
prop_area
*
map_result
=
map_fd_rw
(
fd
);
close
(
fd
);
return
map_result
;
}
void
*
prop_area
::
allocate_obj
(
const
size_t
size
,
uint_least32_t
*
const
off
)
{
const
size_t
aligned
=
BIONIC_ALIGN
(
size
,
sizeof
(
uint_least32_t
));
if
(
bytes_used_
+
aligned
>
pa_data_size
)
{
return
nullptr
;
}
*
off
=
bytes_used_
;
bytes_used_
+=
aligned
;
return
data_
+
*
off
;
}
prop_bt
*
prop_area
::
new_prop_bt
(
const
char
*
name
,
uint32_t
namelen
,
uint_least32_t
*
const
off
)
{
uint_least32_t
new_offset
;
void
*
const
p
=
allocate_obj
(
sizeof
(
prop_bt
)
+
namelen
+
1
,
&
new_offset
);
if
(
p
!=
nullptr
)
{
prop_bt
*
bt
=
new
(
p
)
prop_bt
(
name
,
namelen
);
*
off
=
new_offset
;
return
bt
;
}
return
nullptr
;
}
prop_info
*
prop_area
::
new_prop_info
(
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
uint_least32_t
*
const
off
)
{
uint_least32_t
new_offset
;
void
*
const
p
=
allocate_obj
(
sizeof
(
prop_info
)
+
namelen
+
1
,
&
new_offset
);
if
(
p
!=
nullptr
)
{
prop_info
*
info
=
new
(
p
)
prop_info
(
name
,
namelen
,
value
,
valuelen
);
*
off
=
new_offset
;
return
info
;
}
return
nullptr
;
}
void
*
prop_area
::
to_prop_obj
(
uint_least32_t
off
)
{
if
(
off
>
pa_data_size
)
return
nullptr
;
return
(
data_
+
off
);
}
inline
prop_bt
*
prop_area
::
to_prop_bt
(
atomic_uint_least32_t
*
off_p
)
{
uint_least32_t
off
=
atomic_load_explicit
(
off_p
,
memory_order_consume
);
return
reinterpret_cast
<
prop_bt
*>
(
to_prop_obj
(
off
));
}
inline
prop_info
*
prop_area
::
to_prop_info
(
atomic_uint_least32_t
*
off_p
)
{
uint_least32_t
off
=
atomic_load_explicit
(
off_p
,
memory_order_consume
);
return
reinterpret_cast
<
prop_info
*>
(
to_prop_obj
(
off
));
}
inline
prop_bt
*
prop_area
::
root_node
()
{
return
reinterpret_cast
<
prop_bt
*>
(
to_prop_obj
(
0
));
}
static
int
cmp_prop_name
(
const
char
*
one
,
uint32_t
one_len
,
const
char
*
two
,
uint32_t
two_len
)
{
if
(
one_len
<
two_len
)
return
-
1
;
else
if
(
one_len
>
two_len
)
return
1
;
else
return
strncmp
(
one
,
two
,
one_len
);
}
prop_bt
*
prop_area
::
find_prop_bt
(
prop_bt
*
const
bt
,
const
char
*
name
,
uint32_t
namelen
,
bool
alloc_if_needed
)
{
prop_bt
*
current
=
bt
;
while
(
true
)
{
if
(
!
current
)
{
return
nullptr
;
}
const
int
ret
=
cmp_prop_name
(
name
,
namelen
,
current
->
name
,
current
->
namelen
);
if
(
ret
==
0
)
{
return
current
;
}
if
(
ret
<
0
)
{
uint_least32_t
left_offset
=
atomic_load_explicit
(
&
current
->
left
,
memory_order_relaxed
);
if
(
left_offset
!=
0
)
{
current
=
to_prop_bt
(
&
current
->
left
);
}
else
{
if
(
!
alloc_if_needed
)
{
return
nullptr
;
}
uint_least32_t
new_offset
;
prop_bt
*
new_bt
=
new_prop_bt
(
name
,
namelen
,
&
new_offset
);
if
(
new_bt
)
{
atomic_store_explicit
(
&
current
->
left
,
new_offset
,
memory_order_release
);
}
return
new_bt
;
}
}
else
{
uint_least32_t
right_offset
=
atomic_load_explicit
(
&
current
->
right
,
memory_order_relaxed
);
if
(
right_offset
!=
0
)
{
current
=
to_prop_bt
(
&
current
->
right
);
}
else
{
if
(
!
alloc_if_needed
)
{
return
nullptr
;
}
uint_least32_t
new_offset
;
prop_bt
*
new_bt
=
new_prop_bt
(
name
,
namelen
,
&
new_offset
);
if
(
new_bt
)
{
atomic_store_explicit
(
&
current
->
right
,
new_offset
,
memory_order_release
);
}
return
new_bt
;
}
}
}
}
const
prop_info
*
prop_area
::
find_property
(
prop_bt
*
const
trie
,
const
char
*
name
,
uint32_t
namelen
,
const
char
*
value
,
uint32_t
valuelen
,
bool
alloc_if_needed
)
{
if
(
!
trie
)
return
nullptr
;
const
char
*
remaining_name
=
name
;
prop_bt
*
current
=
trie
;
while
(
true
)
{
const
char
*
sep
=
strchr
(
remaining_name
,
'.'
);
const
bool
want_subtree
=
(
sep
!=
nullptr
);
const
uint32_t
substr_size
=
(
want_subtree
)
?
sep
-
remaining_name
:
strlen
(
remaining_name
);
if
(
!
substr_size
)
{
return
nullptr
;
}
prop_bt
*
root
=
nullptr
;
uint_least32_t
children_offset
=
atomic_load_explicit
(
&
current
->
children
,
memory_order_relaxed
);
if
(
children_offset
!=
0
)
{
root
=
to_prop_bt
(
&
current
->
children
);
}
else
if
(
alloc_if_needed
)
{
uint_least32_t
new_offset
;
root
=
new_prop_bt
(
remaining_name
,
substr_size
,
&
new_offset
);
if
(
root
)
{
atomic_store_explicit
(
&
current
->
children
,
new_offset
,
memory_order_release
);
}
}
if
(
!
root
)
{
return
nullptr
;
}
current
=
find_prop_bt
(
root
,
remaining_name
,
substr_size
,
alloc_if_needed
);
if
(
!
current
)
{
return
nullptr
;
}
if
(
!
want_subtree
)
break
;
remaining_name
=
sep
+
1
;
}
uint_least32_t
prop_offset
=
atomic_load_explicit
(
&
current
->
prop
,
memory_order_relaxed
);
if
(
prop_offset
!=
0
)
{
return
to_prop_info
(
&
current
->
prop
);
}
else
if
(
alloc_if_needed
)
{
uint_least32_t
new_offset
;
prop_info
*
new_info
=
new_prop_info
(
name
,
namelen
,
value
,
valuelen
,
&
new_offset
);
if
(
new_info
)
{
atomic_store_explicit
(
&
current
->
prop
,
new_offset
,
memory_order_release
);
}
return
new_info
;
}
else
{
return
nullptr
;
}
}
bool
prop_area
::
find_property_and_del
(
prop_bt
*
const
trie
,
const
char
*
name
)
{
if
(
!
trie
)
return
false
;
const
char
*
remaining_name
=
name
;
prop_bt
*
current
=
trie
;
while
(
true
)
{
const
char
*
sep
=
strchr
(
remaining_name
,
'.'
);
const
bool
want_subtree
=
(
sep
!=
nullptr
);
const
uint32_t
substr_size
=
(
want_subtree
)
?
sep
-
remaining_name
:
strlen
(
remaining_name
);
if
(
!
substr_size
)
{
return
false
;
}
prop_bt
*
root
=
nullptr
;
uint_least32_t
children_offset
=
atomic_load_explicit
(
&
current
->
children
,
memory_order_relaxed
);
if
(
children_offset
!=
0
)
{
root
=
to_prop_bt
(
&
current
->
children
);
}
if
(
!
root
)
{
return
false
;
}
current
=
find_prop_bt
(
root
,
remaining_name
,
substr_size
,
false
);
if
(
!
current
)
{
return
false
;
}
if
(
!
want_subtree
)
break
;
remaining_name
=
sep
+
1
;
}
uint_least32_t
prop_offset
=
atomic_load_explicit
(
&
current
->
prop
,
memory_order_relaxed
);
if
(
prop_offset
!=
0
)
{
atomic_store_explicit
(
&
current
->
prop
,
0
,
memory_order_release
);
return
true
;
}
else
{
return
false
;
}
}
class
PropertyServiceConnection
{
public
:
PropertyServiceConnection
()
:
last_error_
(
0
)
{
socket_
=
::
socket
(
AF_LOCAL
,
SOCK_STREAM
|
SOCK_CLOEXEC
,
0
);
if
(
socket_
==
-
1
)
{
last_error_
=
errno
;
return
;
}
const
size_t
namelen
=
strlen
(
property_service_socket
);
sockaddr_un
addr
;
memset
(
&
addr
,
0
,
sizeof
(
addr
));
strlcpy
(
addr
.
sun_path
,
property_service_socket
,
sizeof
(
addr
.
sun_path
));
addr
.
sun_family
=
AF_LOCAL
;
socklen_t
alen
=
namelen
+
offsetof
(
sockaddr_un
,
sun_path
)
+
1
;
if
(
TEMP_FAILURE_RETRY
(
connect
(
socket_
,
reinterpret_cast
<
sockaddr
*>
(
&
addr
),
alen
))
==
-
1
)
{
last_error_
=
errno
;
close
(
socket_
);
socket_
=
-
1
;
}
}
bool
IsValid
()
{
return
socket_
!=
-
1
;
}
int
GetLastError
()
{
return
last_error_
;
}
bool
RecvInt32
(
int32_t
*
value
)
{
int
result
=
TEMP_FAILURE_RETRY
(
recv
(
socket_
,
value
,
sizeof
(
*
value
),
MSG_WAITALL
));
return
CheckSendRecvResult
(
result
,
sizeof
(
*
value
));
}
int
socket
()
{
return
socket_
;
}
~
PropertyServiceConnection
()
{
if
(
socket_
!=
-
1
)
{
close
(
socket_
);
}
}
private
:
bool
CheckSendRecvResult
(
int
result
,
int
expected_len
)
{
if
(
result
==
-
1
)
{
last_error_
=
errno
;
}
else
if
(
result
!=
expected_len
)
{
last_error_
=
-
1
;
}
else
{
last_error_
=
0
;
}
return
last_error_
==
0
;
}
int
socket_
;
int
last_error_
;
friend
class
SocketWriter
;
};
class
SocketWriter
{
public
:
explicit
SocketWriter
(
PropertyServiceConnection
*
connection
)
:
connection_
(
connection
),
iov_index_
(
0
),
uint_buf_index_
(
0
)
{}
SocketWriter
&
WriteUint32
(
uint32_t
value
)
{
CHECK
(
uint_buf_index_
<
kUintBufSize
);
CHECK
(
iov_index_
<
kIovSize
);
uint32_t
*
ptr
=
uint_buf_
+
uint_buf_index_
;
uint_buf_
[
uint_buf_index_
++
]
=
value
;
iov_
[
iov_index_
].
iov_base
=
ptr
;
iov_
[
iov_index_
].
iov_len
=
sizeof
(
*
ptr
);
++
iov_index_
;
return
*
this
;
}
SocketWriter
&
WriteString
(
const
char
*
value
)
{
uint32_t
valuelen
=
strlen
(
value
);
WriteUint32
(
valuelen
);
if
(
valuelen
==
0
)
{
return
*
this
;
}
CHECK
(
iov_index_
<
kIovSize
);
iov_
[
iov_index_
].
iov_base
=
const_cast
<
char
*>
(
value
);
iov_
[
iov_index_
].
iov_len
=
valuelen
;
++
iov_index_
;
return
*
this
;
}
bool
Send
()
{
if
(
!
connection_
->
IsValid
())
{
return
false
;
}
if
(
writev
(
connection_
->
socket
(),
iov_
,
iov_index_
)
==
-
1
)
{
connection_
->
last_error_
=
errno
;
return
false
;
}
iov_index_
=
uint_buf_index_
=
0
;
return
true
;
}
private
:
static
constexpr
size_t
kUintBufSize
=
8
;
static
constexpr
size_t
kIovSize
=
8
;
PropertyServiceConnection
*
connection_
;
iovec
iov_
[
kIovSize
];
size_t
iov_index_
;
uint32_t
uint_buf_
[
kUintBufSize
];
size_t
uint_buf_index_
;
DISALLOW_IMPLICIT_CONSTRUCTORS
(
SocketWriter
);
};
struct
prop_msg
{
unsigned
cmd
;
char
name
[
PROP_NAME_MAX
];
char
value
[
PROP_VALUE_MAX
];
};
static
int
send_prop_msg
(
const
prop_msg
*
msg
)
{
PropertyServiceConnection
connection
;
if
(
!
connection
.
IsValid
())
{
return
connection
.
GetLastError
();
}
int
result
=
-
1
;
int
s
=
connection
.
socket
();
const
int
num_bytes
=
TEMP_FAILURE_RETRY
(
send
(
s
,
msg
,
sizeof
(
prop_msg
),
0
));
if
(
num_bytes
==
sizeof
(
prop_msg
))
{
// We successfully wrote to the property server but now we
// wait for the property server to finish its work. It
// acknowledges its completion by closing the socket so we
// poll here (on nothing), waiting for the socket to close.
// If you 'adb shell setprop foo bar' you'll see the POLLHUP
// once the socket closes. Out of paranoia we cap our poll
// at 250 ms.
pollfd
pollfds
[
1
];
pollfds
[
0
].
fd
=
s
;
pollfds
[
0
].
events
=
0
;
const
int
poll_result
=
TEMP_FAILURE_RETRY
(
poll
(
pollfds
,
1
,
250
/* ms */
));
if
(
poll_result
==
1
&&
(
pollfds
[
0
].
revents
&
POLLHUP
)
!=
0
)
{
result
=
0
;
}
else
{
// Ignore the timeout and treat it like a success anyway.
// The init process is single-threaded and its property
// service is sometimes slow to respond (perhaps it's off
// starting a child process or something) and thus this
// times out and the caller thinks it failed, even though
// it's still getting around to it. So we fake it here,
// mostly for ctl.* properties, but we do try and wait 250
// ms so callers who do read-after-write can reliably see
// what they've written. Most of the time.
// TODO: fix the system properties design.
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Property service has timed out while trying to set
\"
%s
\"
to
\"
%s
\"
"
,
msg
->
name
,
msg
->
value
);
result
=
0
;
}
}
return
result
;
}
bool
prop_area
::
foreach_property
(
prop_bt
*
const
trie
,
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
if
(
!
trie
)
return
false
;
uint_least32_t
left_offset
=
atomic_load_explicit
(
&
trie
->
left
,
memory_order_relaxed
);
if
(
left_offset
!=
0
)
{
const
int
err
=
foreach_property
(
to_prop_bt
(
&
trie
->
left
),
propfn
,
cookie
);
if
(
err
<
0
)
return
false
;
}
uint_least32_t
prop_offset
=
atomic_load_explicit
(
&
trie
->
prop
,
memory_order_relaxed
);
if
(
prop_offset
!=
0
)
{
prop_info
*
info
=
to_prop_info
(
&
trie
->
prop
);
if
(
!
info
)
return
false
;
propfn
(
info
,
cookie
);
}
uint_least32_t
children_offset
=
atomic_load_explicit
(
&
trie
->
children
,
memory_order_relaxed
);
if
(
children_offset
!=
0
)
{
const
int
err
=
foreach_property
(
to_prop_bt
(
&
trie
->
children
),
propfn
,
cookie
);
if
(
err
<
0
)
return
false
;
}
uint_least32_t
right_offset
=
atomic_load_explicit
(
&
trie
->
right
,
memory_order_relaxed
);
if
(
right_offset
!=
0
)
{
const
int
err
=
foreach_property
(
to_prop_bt
(
&
trie
->
right
),
propfn
,
cookie
);
if
(
err
<
0
)
return
false
;
}
return
true
;
}
const
prop_info
*
prop_area
::
find
(
const
char
*
name
)
{
return
find_property
(
root_node
(),
name
,
strlen
(
name
),
nullptr
,
0
,
false
);
}
bool
prop_area
::
del
(
const
char
*
name
)
{
return
find_property_and_del
(
root_node
(),
name
);
}
bool
prop_area
::
add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
)
{
return
find_property
(
root_node
(),
name
,
namelen
,
value
,
valuelen
,
true
);
}
bool
prop_area
::
foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
return
foreach_property
(
root_node
(),
propfn
,
cookie
);
}
class
context_node
{
public
:
context_node
(
context_node
*
next
,
const
char
*
context
,
prop_area
*
pa
)
:
next
(
next
),
context_
(
strdup
(
context
)),
pa_
(
pa
),
no_access_
(
false
)
{
lock_
.
init
(
false
);
}
~
context_node
()
{
unmap
();
free
(
context_
);
}
bool
open
(
bool
access_rw
,
bool
*
fsetxattr_failed
);
bool
check_access_and_open
();
void
reset_access
();
const
char
*
context
()
const
{
return
context_
;
}
prop_area
*
pa
()
{
return
pa_
;
}
context_node
*
next
;
private
:
bool
check_access
();
void
unmap
();
Lock
lock_
;
char
*
context_
;
prop_area
*
pa_
;
bool
no_access_
;
};
struct
prefix_node
{
prefix_node
(
struct
prefix_node
*
next
,
const
char
*
prefix
,
context_node
*
context
)
:
prefix
(
strdup
(
prefix
)),
prefix_len
(
strlen
(
prefix
)),
context
(
context
),
next
(
next
)
{
}
~
prefix_node
()
{
free
(
prefix
);
}
char
*
prefix
;
const
size_t
prefix_len
;
context_node
*
context
;
struct
prefix_node
*
next
;
};
template
<
typename
List
,
typename
...
Args
>
static
inline
void
list_add
(
List
**
list
,
Args
...
args
)
{
*
list
=
new
List
(
*
list
,
args
...);
}
static
void
list_add_after_len
(
prefix_node
**
list
,
const
char
*
prefix
,
context_node
*
context
)
{
size_t
prefix_len
=
strlen
(
prefix
);
auto
next_list
=
list
;
while
(
*
next_list
)
{
if
((
*
next_list
)
->
prefix_len
<
prefix_len
||
(
*
next_list
)
->
prefix
[
0
]
==
'*'
)
{
list_add
(
next_list
,
prefix
,
context
);
return
;
}
next_list
=
&
(
*
next_list
)
->
next
;
}
list_add
(
next_list
,
prefix
,
context
);
}
template
<
typename
List
,
typename
Func
>
static
void
list_foreach
(
List
*
list
,
Func
func
)
{
while
(
list
)
{
func
(
list
);
list
=
list
->
next
;
}
}
template
<
typename
List
,
typename
Func
>
static
List
*
list_find
(
List
*
list
,
Func
func
)
{
while
(
list
)
{
if
(
func
(
list
))
{
return
list
;
}
list
=
list
->
next
;
}
return
nullptr
;
}
template
<
typename
List
>
static
void
list_free
(
List
**
list
)
{
while
(
*
list
)
{
auto
old_list
=
*
list
;
*
list
=
old_list
->
next
;
delete
old_list
;
}
}
static
prefix_node
*
prefixes
=
nullptr
;
static
context_node
*
contexts
=
nullptr
;
/*
* pthread_mutex_lock() calls into system_properties in the case of contention.
* This creates a risk of dead lock if any system_properties functions
* use pthread locks after system_property initialization.
*
* For this reason, the below three functions use a bionic Lock and static
* allocation of memory for each filename.
*/
bool
context_node
::
open
(
bool
access_rw
,
bool
*
fsetxattr_failed
)
{
lock_
.
lock
();
if
(
pa_
)
{
lock_
.
unlock
();
return
true
;
}
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
property_filename
,
context_
);
if
(
len
<
0
||
len
>
PROP_FILENAME_MAX
)
{
lock_
.
unlock
();
return
false
;
}
if
(
access_rw
)
{
pa_
=
map_prop_area_rw
(
filename
,
context_
,
fsetxattr_failed
);
}
else
{
pa_
=
map_prop_area
(
filename
);
}
lock_
.
unlock
();
return
pa_
;
}
bool
context_node
::
check_access_and_open
()
{
if
(
!
pa_
&&
!
no_access_
)
{
if
(
!
check_access
()
||
!
open
(
false
,
nullptr
))
{
no_access_
=
true
;
}
}
return
pa_
;
}
void
context_node
::
reset_access
()
{
if
(
!
check_access
())
{
unmap
();
no_access_
=
true
;
}
else
{
no_access_
=
false
;
}
}
bool
context_node
::
check_access
()
{
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
property_filename
,
context_
);
if
(
len
<
0
||
len
>
PROP_FILENAME_MAX
)
{
return
false
;
}
return
access
(
filename
,
R_OK
)
==
0
;
}
void
context_node
::
unmap
()
{
if
(
!
pa_
)
{
return
;
}
munmap
(
pa_
,
pa_size
);
if
(
pa_
==
__system_property_area__
)
{
__system_property_area__
=
nullptr
;
}
pa_
=
nullptr
;
}
static
bool
map_system_property_area
(
bool
access_rw
,
bool
*
fsetxattr_failed
)
{
char
filename
[
PROP_FILENAME_MAX
];
int
len
=
async_safe_format_buffer
(
filename
,
sizeof
(
filename
),
"%s/properties_serial"
,
property_filename
);
if
(
len
<
0
||
len
>
PROP_FILENAME_MAX
)
{
__system_property_area__
=
nullptr
;
return
false
;
}
if
(
access_rw
)
{
__system_property_area__
=
map_prop_area_rw
(
filename
,
"u:object_r:properties_serial:s0"
,
fsetxattr_failed
);
}
else
{
__system_property_area__
=
map_prop_area
(
filename
);
}
return
__system_property_area__
;
}
static
prop_area
*
get_prop_area_for_name
(
const
char
*
name
)
{
auto
entry
=
list_find
(
prefixes
,
[
name
](
prefix_node
*
l
)
{
return
l
->
prefix
[
0
]
==
'*'
||
!
strncmp
(
l
->
prefix
,
name
,
l
->
prefix_len
);
});
if
(
!
entry
)
{
return
nullptr
;
}
auto
cnode
=
entry
->
context
;
if
(
!
cnode
->
pa
())
{
/*
* We explicitly do not check no_access_ in this case because unlike the
* case of foreach(), we want to generate an selinux audit for each
* non-permitted property access in this function.
*/
cnode
->
open
(
false
,
nullptr
);
}
return
cnode
->
pa
();
}
/*
* The below two functions are duplicated from label_support.c in libselinux.
* TODO: Find a location suitable for these functions such that both libc and
* libselinux can share a common source file.
*/
/*
* The read_spec_entries and read_spec_entry functions may be used to
* replace sscanf to read entries from spec files. The file and
* property services now use these.
*/
/* Read an entry from a spec file (e.g. file_contexts) */
static
inline
int
read_spec_entry
(
char
**
entry
,
char
**
ptr
,
int
*
len
)
{
*
entry
=
nullptr
;
char
*
tmp_buf
=
nullptr
;
while
(
isspace
(
**
ptr
)
&&
**
ptr
!=
'\0'
)
(
*
ptr
)
++
;
tmp_buf
=
*
ptr
;
*
len
=
0
;
while
(
!
isspace
(
**
ptr
)
&&
**
ptr
!=
'\0'
)
{
(
*
ptr
)
++
;
(
*
len
)
++
;
}
if
(
*
len
)
{
*
entry
=
strndup
(
tmp_buf
,
*
len
);
if
(
!*
entry
)
return
-
1
;
}
return
0
;
}
/*
* line_buf - Buffer containing the spec entries .
* num_args - The number of spec parameter entries to process.
* ... - A 'char **spec_entry' for each parameter.
* returns - The number of items processed.
*
* This function calls read_spec_entry() to do the actual string processing.
*/
static
int
read_spec_entries
(
char
*
line_buf
,
int
num_args
,
...)
{
char
**
spec_entry
,
*
buf_p
;
int
len
,
rc
,
items
,
entry_len
=
0
;
va_list
ap
;
len
=
strlen
(
line_buf
);
if
(
line_buf
[
len
-
1
]
==
'\n'
)
line_buf
[
len
-
1
]
=
'\0'
;
else
/* Handle case if line not \n terminated by bumping
* the len for the check below (as the line is NUL
* terminated by getline(3)) */
len
++
;
buf_p
=
line_buf
;
while
(
isspace
(
*
buf_p
))
buf_p
++
;
/* Skip comment lines and empty lines. */
if
(
*
buf_p
==
'#'
||
*
buf_p
==
'\0'
)
return
0
;
/* Process the spec file entries */
va_start
(
ap
,
num_args
);
items
=
0
;
while
(
items
<
num_args
)
{
spec_entry
=
va_arg
(
ap
,
char
**
);
if
(
len
-
1
==
buf_p
-
line_buf
)
{
va_end
(
ap
);
return
items
;
}
rc
=
read_spec_entry
(
spec_entry
,
&
buf_p
,
&
entry_len
);
if
(
rc
<
0
)
{
va_end
(
ap
);
return
rc
;
}
if
(
entry_len
)
items
++
;
}
va_end
(
ap
);
return
items
;
}
static
bool
initialize_properties_from_file
(
const
char
*
filename
)
{
FILE
*
file
=
fopen
(
filename
,
"re"
);
if
(
!
file
)
{
return
false
;
}
char
*
buffer
=
nullptr
;
size_t
line_len
;
char
*
prop_prefix
=
nullptr
;
char
*
context
=
nullptr
;
while
(
getline
(
&
buffer
,
&
line_len
,
file
)
>
0
)
{
int
items
=
read_spec_entries
(
buffer
,
2
,
&
prop_prefix
,
&
context
);
if
(
items
<=
0
)
{
continue
;
}
if
(
items
==
1
)
{
free
(
prop_prefix
);
continue
;
}
/*
* init uses ctl.* properties as an IPC mechanism and does not write them
* to a property file, therefore we do not need to create property files
* to store them.
*/
if
(
!
strncmp
(
prop_prefix
,
"ctl."
,
4
))
{
free
(
prop_prefix
);
free
(
context
);
continue
;
}
auto
old_context
=
list_find
(
contexts
,
[
context
](
context_node
*
l
)
{
return
!
strcmp
(
l
->
context
(),
context
);
});
if
(
old_context
)
{
list_add_after_len
(
&
prefixes
,
prop_prefix
,
old_context
);
}
else
{
list_add
(
&
contexts
,
context
,
nullptr
);
list_add_after_len
(
&
prefixes
,
prop_prefix
,
contexts
);
}
free
(
prop_prefix
);
free
(
context
);
}
free
(
buffer
);
fclose
(
file
);
return
true
;
}
static
bool
initialize_properties
()
{
// If we do find /property_contexts, then this is being
// run as part of the OTA updater on older release that had
// /property_contexts - b/34370523
if
(
initialize_properties_from_file
(
"/property_contexts"
))
{
return
true
;
}
// Use property_contexts from /system & /vendor, fall back to those from /
if
(
access
(
"/system/etc/selinux/plat_property_contexts"
,
R_OK
)
!=
-
1
)
{
if
(
!
initialize_properties_from_file
(
"/system/etc/selinux/plat_property_contexts"
))
{
return
false
;
}
// Don't check for failure here, so we always have a sane list of properties.
// E.g. In case of recovery, the vendor partition will not have mounted and we
// still need the system / platform properties to function.
initialize_properties_from_file
(
"/vendor/etc/selinux/nonplat_property_contexts"
)
||
initialize_properties_from_file
(
"/vendor/etc/selinux/vendor_property_contexts"
);
}
else
{
if
(
!
initialize_properties_from_file
(
"/plat_property_contexts"
))
{
return
false
;
}
initialize_properties_from_file
(
"/nonplat_property_contexts"
);
}
return
true
;
}
static
bool
is_dir
(
const
char
*
pathname
)
{
struct
stat
info
;
if
(
stat
(
pathname
,
&
info
)
==
-
1
)
{
return
false
;
}
return
S_ISDIR
(
info
.
st_mode
);
}
static
void
free_and_unmap_contexts
()
{
list_free
(
&
prefixes
);
list_free
(
&
contexts
);
if
(
__system_property_area__
)
{
munmap
(
__system_property_area__
,
pa_size
);
__system_property_area__
=
nullptr
;
}
}
int
__system_properties_init
()
{
// This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
// ErrnoRestorer errno_restorer;
if
(
initialized
)
{
// list_foreach(contexts, [](context_node* l) { l->reset_access(); }); // resetprop remove
return
0
;
}
if
(
is_dir
(
property_filename
))
{
if
(
!
initialize_properties
())
{
return
-
1
;
}
if
(
!
map_system_property_area
(
false
,
nullptr
))
{
free_and_unmap_contexts
();
return
-
1
;
}
}
else
{
__system_property_area__
=
map_prop_area
(
property_filename
);
if
(
!
__system_property_area__
)
{
return
-
1
;
}
list_add
(
&
contexts
,
"legacy_system_prop_area"
,
__system_property_area__
);
list_add_after_len
(
&
prefixes
,
"*"
,
contexts
);
}
initialized
=
true
;
return
0
;
}
int
__system_property_set_filename
(
const
char
*
filename
)
{
size_t
len
=
strlen
(
filename
);
if
(
len
>=
sizeof
(
property_filename
))
return
-
1
;
strcpy
(
property_filename
,
filename
);
return
0
;
}
int
__system_property_area_init
()
{
free_and_unmap_contexts
();
mkdir
(
property_filename
,
S_IRWXU
|
S_IXGRP
|
S_IXOTH
);
if
(
!
initialize_properties
())
{
return
-
1
;
}
bool
open_failed
=
false
;
bool
fsetxattr_failed
=
false
;
list_foreach
(
contexts
,
[
&
fsetxattr_failed
,
&
open_failed
](
context_node
*
l
)
{
if
(
!
l
->
open
(
true
,
&
fsetxattr_failed
))
{
open_failed
=
true
;
}
});
if
(
open_failed
||
!
map_system_property_area
(
true
,
&
fsetxattr_failed
))
{
free_and_unmap_contexts
();
return
-
1
;
}
initialized
=
true
;
return
fsetxattr_failed
?
-
2
:
0
;
}
uint32_t
__system_property_area_serial
()
{
prop_area
*
pa
=
__system_property_area__
;
if
(
!
pa
)
{
return
-
1
;
}
// Make sure this read fulfilled before __system_property_serial
return
atomic_load_explicit
(
pa
->
serial
(),
memory_order_acquire
);
}
const
prop_info
*
__system_property_find
(
const
char
*
name
)
{
if
(
!
__system_property_area__
)
{
return
nullptr
;
}
prop_area
*
pa
=
get_prop_area_for_name
(
name
);
if
(
!
pa
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"Access denied finding property
\"
%s
\"
"
,
name
);
return
nullptr
;
}
return
pa
->
find
(
name
);
}
int
__system_property_del
(
const
char
*
name
)
{
if
(
!
__system_property_area__
)
{
return
1
;
}
prop_area
*
pa
=
get_prop_area_for_name
(
name
);
if
(
!
pa
)
{
return
1
;
}
if
(
!
pa
->
del
(
name
))
return
1
;
// We want to make sure that updates are visible to readers
atomic_store_explicit
(
__system_property_area__
->
serial
(),
atomic_load_explicit
(
__system_property_area__
->
serial
(),
memory_order_relaxed
)
+
1
,
memory_order_release
);
__futex_wake
(
__system_property_area__
->
serial
(),
INT32_MAX
);
return
0
;
}
// The C11 standard doesn't allow atomic loads from const fields,
// though C++11 does. Fudge it until standards get straightened out.
static
inline
uint_least32_t
load_const_atomic
(
const
atomic_uint_least32_t
*
s
,
memory_order
mo
)
{
atomic_uint_least32_t
*
non_const_s
=
const_cast
<
atomic_uint_least32_t
*>
(
s
);
return
atomic_load_explicit
(
non_const_s
,
mo
);
}
int
__system_property_read
(
const
prop_info
*
pi
,
char
*
name
,
char
*
value
)
{
while
(
true
)
{
uint32_t
serial
=
__system_property_serial
(
pi
);
// acquire semantics
size_t
len
=
SERIAL_VALUE_LEN
(
serial
);
memcpy
(
value
,
pi
->
value
,
len
+
1
);
// TODO: Fix the synchronization scheme here.
// There is no fully supported way to implement this kind
// of synchronization in C++11, since the memcpy races with
// updates to pi, and the data being accessed is not atomic.
// The following fence is unintuitive, but would be the
// correct one if memcpy used memory_order_relaxed atomic accesses.
// In practice it seems unlikely that the generated code would
// would be any different, so this should be OK.
atomic_thread_fence
(
memory_order_acquire
);
if
(
serial
==
load_const_atomic
(
&
(
pi
->
serial
),
memory_order_relaxed
))
{
if
(
name
!=
nullptr
)
{
size_t
namelen
=
strlcpy
(
name
,
pi
->
name
,
PROP_NAME_MAX
);
if
(
namelen
>=
PROP_NAME_MAX
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"The property name length for
\"
%s
\"
is >= %d;"
" please use __system_property_read_callback"
" to read this property. (the name is truncated to
\"
%s
\"
)"
,
pi
->
name
,
PROP_NAME_MAX
-
1
,
name
);
}
}
return
len
;
}
}
}
void
__system_property_read_callback
(
const
prop_info
*
pi
,
void
(
*
callback
)(
void
*
cookie
,
const
char
*
name
,
const
char
*
value
,
uint32_t
serial
),
void
*
cookie
)
{
while
(
true
)
{
uint32_t
serial
=
__system_property_serial
(
pi
);
// acquire semantics
size_t
len
=
SERIAL_VALUE_LEN
(
serial
);
char
value_buf
[
len
+
1
];
memcpy
(
value_buf
,
pi
->
value
,
len
);
value_buf
[
len
]
=
'\0'
;
// TODO: see todo in __system_property_read function
atomic_thread_fence
(
memory_order_acquire
);
if
(
serial
==
load_const_atomic
(
&
(
pi
->
serial
),
memory_order_relaxed
))
{
callback
(
cookie
,
pi
->
name
,
value_buf
,
serial
);
return
;
}
}
}
int
__system_property_get
(
const
char
*
name
,
char
*
value
)
{
const
prop_info
*
pi
=
__system_property_find
(
name
);
if
(
pi
!=
0
)
{
return
__system_property_read
(
pi
,
nullptr
,
value
);
}
else
{
value
[
0
]
=
0
;
return
0
;
}
}
static
constexpr
uint32_t
kProtocolVersion1
=
1
;
static
constexpr
uint32_t
kProtocolVersion2
=
2
;
// current
static
uint32_t
g_propservice_protocol_version
=
0
;
static
void
detect_protocol_version
()
{
char
value
[
PROP_VALUE_MAX
];
if
(
__system_property_get
(
kServiceVersionPropertyName
,
value
)
==
0
)
{
g_propservice_protocol_version
=
kProtocolVersion1
;
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Using old property service protocol (
\"
%s
\"
is not set)"
,
kServiceVersionPropertyName
);
}
else
{
uint32_t
version
=
static_cast
<
uint32_t
>
(
atoll
(
value
));
if
(
version
>=
kProtocolVersion2
)
{
g_propservice_protocol_version
=
kProtocolVersion2
;
}
else
{
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Using old property service protocol (
\"
%s
\"
=
\"
%s
\"
)"
,
kServiceVersionPropertyName
,
value
);
g_propservice_protocol_version
=
kProtocolVersion1
;
}
}
}
int
__system_property_set
(
const
char
*
key
,
const
char
*
value
)
{
if
(
key
==
nullptr
)
return
-
1
;
if
(
value
==
nullptr
)
value
=
""
;
if
(
strlen
(
value
)
>=
PROP_VALUE_MAX
)
return
-
1
;
if
(
g_propservice_protocol_version
==
0
)
{
detect_protocol_version
();
}
if
(
g_propservice_protocol_version
==
kProtocolVersion1
)
{
// Old protocol does not support long names
if
(
strlen
(
key
)
>=
PROP_NAME_MAX
)
return
-
1
;
prop_msg
msg
;
memset
(
&
msg
,
0
,
sizeof
msg
);
msg
.
cmd
=
PROP_MSG_SETPROP
;
strlcpy
(
msg
.
name
,
key
,
sizeof
msg
.
name
);
strlcpy
(
msg
.
value
,
value
,
sizeof
msg
.
value
);
return
send_prop_msg
(
&
msg
);
}
else
{
// Use proper protocol
PropertyServiceConnection
connection
;
if
(
!
connection
.
IsValid
())
{
errno
=
connection
.
GetLastError
();
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: connection failed; errno=%d (%s)"
,
key
,
value
,
errno
,
strerror
(
errno
));
return
-
1
;
}
SocketWriter
writer
(
&
connection
);
if
(
!
writer
.
WriteUint32
(
PROP_MSG_SETPROP2
).
WriteString
(
key
).
WriteString
(
value
).
Send
())
{
errno
=
connection
.
GetLastError
();
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: write failed; errno=%d (%s)"
,
key
,
value
,
errno
,
strerror
(
errno
));
return
-
1
;
}
int
result
=
-
1
;
if
(
!
connection
.
RecvInt32
(
&
result
))
{
errno
=
connection
.
GetLastError
();
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: recv failed; errno=%d (%s)"
,
key
,
value
,
errno
,
strerror
(
errno
));
return
-
1
;
}
if
(
result
!=
PROP_SUCCESS
)
{
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: error code: 0x%x"
,
key
,
value
,
result
);
return
-
1
;
}
return
0
;
}
}
int
__system_property_update
(
prop_info
*
pi
,
const
char
*
value
,
unsigned
int
len
)
{
if
(
len
>=
PROP_VALUE_MAX
)
{
return
-
1
;
}
prop_area
*
pa
=
__system_property_area__
;
if
(
!
pa
)
{
return
-
1
;
}
uint32_t
serial
=
atomic_load_explicit
(
&
pi
->
serial
,
memory_order_relaxed
);
serial
|=
1
;
atomic_store_explicit
(
&
pi
->
serial
,
serial
,
memory_order_relaxed
);
// The memcpy call here also races. Again pretend it
// used memory_order_relaxed atomics, and use the analogous
// counterintuitive fence.
atomic_thread_fence
(
memory_order_release
);
strlcpy
(
pi
->
value
,
value
,
len
+
1
);
atomic_store_explicit
(
&
pi
->
serial
,
(
len
<<
24
)
|
((
serial
+
1
)
&
0xffffff
),
memory_order_release
);
__futex_wake
(
&
pi
->
serial
,
INT32_MAX
);
atomic_store_explicit
(
pa
->
serial
(),
atomic_load_explicit
(
pa
->
serial
(),
memory_order_relaxed
)
+
1
,
memory_order_release
);
__futex_wake
(
pa
->
serial
(),
INT32_MAX
);
return
0
;
}
int
__system_property_add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
)
{
if
(
valuelen
>=
PROP_VALUE_MAX
)
{
return
-
1
;
}
if
(
namelen
<
1
)
{
return
-
1
;
}
if
(
!
__system_property_area__
)
{
return
-
1
;
}
prop_area
*
pa
=
get_prop_area_for_name
(
name
);
if
(
!
pa
)
{
async_safe_format_log
(
ANDROID_LOG_ERROR
,
"libc"
,
"Access denied adding property
\"
%s
\"
"
,
name
);
return
-
1
;
}
bool
ret
=
pa
->
add
(
name
,
namelen
,
value
,
valuelen
);
if
(
!
ret
)
{
return
-
1
;
}
// There is only a single mutator, but we want to make sure that
// updates are visible to a reader waiting for the update.
atomic_store_explicit
(
__system_property_area__
->
serial
(),
atomic_load_explicit
(
__system_property_area__
->
serial
(),
memory_order_relaxed
)
+
1
,
memory_order_release
);
__futex_wake
(
__system_property_area__
->
serial
(),
INT32_MAX
);
return
0
;
}
// Wait for non-locked serial, and retrieve it with acquire semantics.
uint32_t
__system_property_serial
(
const
prop_info
*
pi
)
{
uint32_t
serial
=
load_const_atomic
(
&
pi
->
serial
,
memory_order_acquire
);
while
(
SERIAL_DIRTY
(
serial
))
{
__futex_wait
(
const_cast
<
atomic_uint_least32_t
*>
(
&
pi
->
serial
),
serial
,
nullptr
);
serial
=
load_const_atomic
(
&
pi
->
serial
,
memory_order_acquire
);
}
return
serial
;
}
uint32_t
__system_property_wait_any
(
uint32_t
old_serial
)
{
uint32_t
new_serial
;
__system_property_wait
(
nullptr
,
old_serial
,
&
new_serial
,
nullptr
);
return
new_serial
;
}
bool
__system_property_wait
(
const
prop_info
*
pi
,
uint32_t
old_serial
,
uint32_t
*
new_serial_ptr
,
const
timespec
*
relative_timeout
)
{
// Are we waiting on the global serial or a specific serial?
atomic_uint_least32_t
*
serial_ptr
;
if
(
pi
==
nullptr
)
{
if
(
__system_property_area__
==
nullptr
)
return
-
1
;
serial_ptr
=
__system_property_area__
->
serial
();
}
else
{
serial_ptr
=
const_cast
<
atomic_uint_least32_t
*>
(
&
pi
->
serial
);
}
uint32_t
new_serial
;
do
{
int
rc
;
if
((
rc
=
__futex_wait
(
serial_ptr
,
old_serial
,
relative_timeout
))
!=
0
&&
rc
==
-
ETIMEDOUT
)
{
return
false
;
}
new_serial
=
load_const_atomic
(
serial_ptr
,
memory_order_acquire
);
}
while
(
new_serial
==
old_serial
);
*
new_serial_ptr
=
new_serial
;
return
true
;
}
const
prop_info
*
__system_property_find_nth
(
unsigned
n
)
{
struct
find_nth
{
const
uint32_t
sought
;
uint32_t
current
;
const
prop_info
*
result
;
explicit
find_nth
(
uint32_t
n
)
:
sought
(
n
),
current
(
0
),
result
(
nullptr
)
{}
static
void
fn
(
const
prop_info
*
pi
,
void
*
ptr
)
{
find_nth
*
self
=
reinterpret_cast
<
find_nth
*>
(
ptr
);
if
(
self
->
current
++
==
self
->
sought
)
self
->
result
=
pi
;
}
}
state
(
n
);
__system_property_foreach
(
find_nth
::
fn
,
&
state
);
return
state
.
result
;
}
int
__system_property_foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
if
(
!
__system_property_area__
)
{
return
-
1
;
}
list_foreach
(
contexts
,
[
propfn
,
cookie
](
context_node
*
l
)
{
if
(
l
->
check_access_and_open
())
{
l
->
pa
()
->
foreach
(
propfn
,
cookie
);
}
});
return
0
;
}
native/jni/resetprop/system_property_api.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
//#include <sys/_system_properties.h>
#include "private/_system_properties.h"
#include <system_properties/prop_area.h>
#include <system_properties/system_properties.h>
#include "private/bionic_defs.h"
static
SystemProperties
system_properties
;
static_assert
(
__is_trivially_constructible
(
SystemProperties
),
"System Properties must be trivially constructable"
);
// This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol.
// It is set to nullptr and never modified.
__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
prop_area
*
__system_property_area__
=
nullptr
;
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_properties_init
()
{
return
system_properties
.
Init
(
PROP_FILENAME
)
?
0
:
-
1
;
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_set_filename
(
const
char
*
)
{
return
-
1
;
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_area_init
()
{
bool
fsetxattr_failed
=
false
;
return
system_properties
.
AreaInit
(
PROP_FILENAME
,
&
fsetxattr_failed
)
&&
!
fsetxattr_failed
?
0
:
-
1
;
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
uint32_t
__system_property_area_serial
()
{
return
system_properties
.
AreaSerial
();
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
const
prop_info
*
__system_property_find
(
const
char
*
name
)
{
return
system_properties
.
Find
(
name
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_read
(
const
prop_info
*
pi
,
char
*
name
,
char
*
value
)
{
return
system_properties
.
Read
(
pi
,
name
,
value
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
void
__system_property_read_callback
(
const
prop_info
*
pi
,
void
(
*
callback
)(
void
*
cookie
,
const
char
*
name
,
const
char
*
value
,
uint32_t
serial
),
void
*
cookie
)
{
return
system_properties
.
ReadCallback
(
pi
,
callback
,
cookie
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_get
(
const
char
*
name
,
char
*
value
)
{
return
system_properties
.
Get
(
name
,
value
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_update
(
prop_info
*
pi
,
const
char
*
value
,
unsigned
int
len
)
{
return
system_properties
.
Update
(
pi
,
value
,
len
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_add
(
const
char
*
name
,
unsigned
int
namelen
,
const
char
*
value
,
unsigned
int
valuelen
)
{
return
system_properties
.
Add
(
name
,
namelen
,
value
,
valuelen
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
uint32_t
__system_property_serial
(
const
prop_info
*
pi
)
{
return
system_properties
.
Serial
(
pi
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
uint32_t
__system_property_wait_any
(
uint32_t
old_serial
)
{
return
system_properties
.
WaitAny
(
old_serial
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
bool
__system_property_wait
(
const
prop_info
*
pi
,
uint32_t
old_serial
,
uint32_t
*
new_serial_ptr
,
const
timespec
*
relative_timeout
)
{
return
system_properties
.
Wait
(
pi
,
old_serial
,
new_serial_ptr
,
relative_timeout
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
const
prop_info
*
__system_property_find_nth
(
unsigned
n
)
{
return
system_properties
.
FindNth
(
n
);
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_foreach
(
void
(
*
propfn
)(
const
prop_info
*
pi
,
void
*
cookie
),
void
*
cookie
)
{
return
system_properties
.
Foreach
(
propfn
,
cookie
);
}
native/jni/resetprop/system_property_set.cpp
0 → 100644
View file @
7a002567
/*
* Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <poll.h>
#include <stdatomic.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
//#include <sys/_system_properties.h>
#include "private/_system_properties.h"
#include <unistd.h>
#include <async_safe/log.h>
#include "private/bionic_defs.h"
#include "private/bionic_macros.h"
static
const
char
property_service_socket
[]
=
"/dev/socket/"
PROP_SERVICE_NAME
;
static
const
char
*
kServiceVersionPropertyName
=
"ro.property_service.version"
;
#define CHECK(x)
/* NOP */
class
PropertyServiceConnection
{
public
:
PropertyServiceConnection
()
:
last_error_
(
0
)
{
socket_
=
::
socket
(
AF_LOCAL
,
SOCK_STREAM
|
SOCK_CLOEXEC
,
0
);
if
(
socket_
==
-
1
)
{
last_error_
=
errno
;
return
;
}
const
size_t
namelen
=
strlen
(
property_service_socket
);
sockaddr_un
addr
;
memset
(
&
addr
,
0
,
sizeof
(
addr
));
strlcpy
(
addr
.
sun_path
,
property_service_socket
,
sizeof
(
addr
.
sun_path
));
addr
.
sun_family
=
AF_LOCAL
;
socklen_t
alen
=
namelen
+
offsetof
(
sockaddr_un
,
sun_path
)
+
1
;
if
(
TEMP_FAILURE_RETRY
(
connect
(
socket_
,
reinterpret_cast
<
sockaddr
*>
(
&
addr
),
alen
))
==
-
1
)
{
last_error_
=
errno
;
close
(
socket_
);
socket_
=
-
1
;
}
}
bool
IsValid
()
{
return
socket_
!=
-
1
;
}
int
GetLastError
()
{
return
last_error_
;
}
bool
RecvInt32
(
int32_t
*
value
)
{
int
result
=
TEMP_FAILURE_RETRY
(
recv
(
socket_
,
value
,
sizeof
(
*
value
),
MSG_WAITALL
));
return
CheckSendRecvResult
(
result
,
sizeof
(
*
value
));
}
int
socket
()
{
return
socket_
;
}
~
PropertyServiceConnection
()
{
if
(
socket_
!=
-
1
)
{
close
(
socket_
);
}
}
private
:
bool
CheckSendRecvResult
(
int
result
,
int
expected_len
)
{
if
(
result
==
-
1
)
{
last_error_
=
errno
;
}
else
if
(
result
!=
expected_len
)
{
last_error_
=
-
1
;
}
else
{
last_error_
=
0
;
}
return
last_error_
==
0
;
}
int
socket_
;
int
last_error_
;
friend
class
SocketWriter
;
};
class
SocketWriter
{
public
:
explicit
SocketWriter
(
PropertyServiceConnection
*
connection
)
:
connection_
(
connection
),
iov_index_
(
0
),
uint_buf_index_
(
0
)
{
}
SocketWriter
&
WriteUint32
(
uint32_t
value
)
{
CHECK
(
uint_buf_index_
<
kUintBufSize
);
CHECK
(
iov_index_
<
kIovSize
);
uint32_t
*
ptr
=
uint_buf_
+
uint_buf_index_
;
uint_buf_
[
uint_buf_index_
++
]
=
value
;
iov_
[
iov_index_
].
iov_base
=
ptr
;
iov_
[
iov_index_
].
iov_len
=
sizeof
(
*
ptr
);
++
iov_index_
;
return
*
this
;
}
SocketWriter
&
WriteString
(
const
char
*
value
)
{
uint32_t
valuelen
=
strlen
(
value
);
WriteUint32
(
valuelen
);
if
(
valuelen
==
0
)
{
return
*
this
;
}
CHECK
(
iov_index_
<
kIovSize
);
iov_
[
iov_index_
].
iov_base
=
const_cast
<
char
*>
(
value
);
iov_
[
iov_index_
].
iov_len
=
valuelen
;
++
iov_index_
;
return
*
this
;
}
bool
Send
()
{
if
(
!
connection_
->
IsValid
())
{
return
false
;
}
if
(
writev
(
connection_
->
socket
(),
iov_
,
iov_index_
)
==
-
1
)
{
connection_
->
last_error_
=
errno
;
return
false
;
}
iov_index_
=
uint_buf_index_
=
0
;
return
true
;
}
private
:
static
constexpr
size_t
kUintBufSize
=
8
;
static
constexpr
size_t
kIovSize
=
8
;
PropertyServiceConnection
*
connection_
;
iovec
iov_
[
kIovSize
];
size_t
iov_index_
;
uint32_t
uint_buf_
[
kUintBufSize
];
size_t
uint_buf_index_
;
DISALLOW_IMPLICIT_CONSTRUCTORS
(
SocketWriter
);
};
struct
prop_msg
{
unsigned
cmd
;
char
name
[
PROP_NAME_MAX
];
char
value
[
PROP_VALUE_MAX
];
};
static
int
send_prop_msg
(
const
prop_msg
*
msg
)
{
PropertyServiceConnection
connection
;
if
(
!
connection
.
IsValid
())
{
return
connection
.
GetLastError
();
}
int
result
=
-
1
;
int
s
=
connection
.
socket
();
const
int
num_bytes
=
TEMP_FAILURE_RETRY
(
send
(
s
,
msg
,
sizeof
(
prop_msg
),
0
));
if
(
num_bytes
==
sizeof
(
prop_msg
))
{
// We successfully wrote to the property server but now we
// wait for the property server to finish its work. It
// acknowledges its completion by closing the socket so we
// poll here (on nothing), waiting for the socket to close.
// If you 'adb shell setprop foo bar' you'll see the POLLHUP
// once the socket closes. Out of paranoia we cap our poll
// at 250 ms.
pollfd
pollfds
[
1
];
pollfds
[
0
].
fd
=
s
;
pollfds
[
0
].
events
=
0
;
const
int
poll_result
=
TEMP_FAILURE_RETRY
(
poll
(
pollfds
,
1
,
250
/* ms */
));
if
(
poll_result
==
1
&&
(
pollfds
[
0
].
revents
&
POLLHUP
)
!=
0
)
{
result
=
0
;
}
else
{
// Ignore the timeout and treat it like a success anyway.
// The init process is single-threaded and its property
// service is sometimes slow to respond (perhaps it's off
// starting a child process or something) and thus this
// times out and the caller thinks it failed, even though
// it's still getting around to it. So we fake it here,
// mostly for ctl.* properties, but we do try and wait 250
// ms so callers who do read-after-write can reliably see
// what they've written. Most of the time.
// TODO: fix the system properties design.
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Property service has timed out while trying to set
\"
%s
\"
to
\"
%s
\"
"
,
msg
->
name
,
msg
->
value
);
result
=
0
;
}
}
return
result
;
}
static
constexpr
uint32_t
kProtocolVersion1
=
1
;
static
constexpr
uint32_t
kProtocolVersion2
=
2
;
// current
static
atomic_uint_least32_t
g_propservice_protocol_version
=
0
;
static
void
detect_protocol_version
()
{
char
value
[
PROP_VALUE_MAX
];
if
(
__system_property_get
(
kServiceVersionPropertyName
,
value
)
==
0
)
{
g_propservice_protocol_version
=
kProtocolVersion1
;
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Using old property service protocol (
\"
%s
\"
is not set)"
,
kServiceVersionPropertyName
);
}
else
{
uint32_t
version
=
static_cast
<
uint32_t
>
(
atoll
(
value
));
if
(
version
>=
kProtocolVersion2
)
{
g_propservice_protocol_version
=
kProtocolVersion2
;
}
else
{
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Using old property service protocol (
\"
%s
\"
=
\"
%s
\"
)"
,
kServiceVersionPropertyName
,
value
);
g_propservice_protocol_version
=
kProtocolVersion1
;
}
}
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
__system_property_set
(
const
char
*
key
,
const
char
*
value
)
{
if
(
key
==
nullptr
)
return
-
1
;
if
(
value
==
nullptr
)
value
=
""
;
if
(
g_propservice_protocol_version
==
0
)
{
detect_protocol_version
();
}
if
(
g_propservice_protocol_version
==
kProtocolVersion1
)
{
// Old protocol does not support long names or values
if
(
strlen
(
key
)
>=
PROP_NAME_MAX
)
return
-
1
;
if
(
strlen
(
value
)
>=
PROP_VALUE_MAX
)
return
-
1
;
prop_msg
msg
;
memset
(
&
msg
,
0
,
sizeof
msg
);
msg
.
cmd
=
PROP_MSG_SETPROP
;
strlcpy
(
msg
.
name
,
key
,
sizeof
msg
.
name
);
strlcpy
(
msg
.
value
,
value
,
sizeof
msg
.
value
);
return
send_prop_msg
(
&
msg
);
}
else
{
// New protocol only allows long values for ro. properties only.
if
(
strlen
(
value
)
>=
PROP_VALUE_MAX
&&
strncmp
(
key
,
"ro."
,
3
)
!=
0
)
return
-
1
;
// Use proper protocol
PropertyServiceConnection
connection
;
if
(
!
connection
.
IsValid
())
{
errno
=
connection
.
GetLastError
();
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: connection failed; errno=%d (%s)"
,
key
,
value
,
errno
,
strerror
(
errno
));
return
-
1
;
}
SocketWriter
writer
(
&
connection
);
if
(
!
writer
.
WriteUint32
(
PROP_MSG_SETPROP2
).
WriteString
(
key
).
WriteString
(
value
).
Send
())
{
errno
=
connection
.
GetLastError
();
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: write failed; errno=%d (%s)"
,
key
,
value
,
errno
,
strerror
(
errno
));
return
-
1
;
}
int
result
=
-
1
;
if
(
!
connection
.
RecvInt32
(
&
result
))
{
errno
=
connection
.
GetLastError
();
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: recv failed; errno=%d (%s)"
,
key
,
value
,
errno
,
strerror
(
errno
));
return
-
1
;
}
if
(
result
!=
PROP_SUCCESS
)
{
async_safe_format_log
(
ANDROID_LOG_WARN
,
"libc"
,
"Unable to set property
\"
%s
\"
to
\"
%s
\"
: error code: 0x%x"
,
key
,
value
,
result
);
return
-
1
;
}
return
0
;
}
}
native/jni/utils/misc.c
View file @
7a002567
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include <sched.h>
#include <sched.h>
#include <unistd.h>
#include <unistd.h>
#include <libgen.h>
#include <libgen.h>
#include <syscall.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/wait.h>
...
@@ -85,80 +86,6 @@ int check_data() {
...
@@ -85,80 +86,6 @@ int check_data() {
return
data
;
return
data
;
}
}
/* Original source: https://opensource.apple.com/source/cvs/cvs-19/cvs/lib/getline.c
* License: GPL 2 or later
* Adjusted to match POSIX */
#define MIN_CHUNK 64
ssize_t
my_getdelim
(
char
**
lineptr
,
size_t
*
n
,
int
delim
,
FILE
*
stream
)
{
size_t
nchars_avail
;
char
*
read_pos
;
if
(
!
lineptr
||
!
n
||
!
stream
)
{
errno
=
EINVAL
;
return
-
1
;
}
if
(
!*
lineptr
)
{
*
n
=
MIN_CHUNK
;
*
lineptr
=
malloc
(
*
n
);
if
(
!*
lineptr
)
{
errno
=
ENOMEM
;
return
-
1
;
}
}
nchars_avail
=
*
n
;
read_pos
=
*
lineptr
;
while
(
1
)
{
int
save_errno
;
register
int
c
=
getc
(
stream
);
save_errno
=
errno
;
if
(
nchars_avail
<
2
)
{
if
(
*
n
>
MIN_CHUNK
)
*
n
*=
2
;
else
*
n
+=
MIN_CHUNK
;
nchars_avail
=
*
n
+
*
lineptr
-
read_pos
;
*
lineptr
=
realloc
(
*
lineptr
,
*
n
);
if
(
!*
lineptr
)
{
errno
=
ENOMEM
;
return
-
1
;
}
read_pos
=
*
n
-
nchars_avail
+
*
lineptr
;
}
if
(
ferror
(
stream
))
{
errno
=
save_errno
;
return
-
1
;
}
if
(
c
==
EOF
)
{
if
(
read_pos
==
*
lineptr
)
return
-
1
;
else
break
;
}
*
read_pos
++
=
c
;
nchars_avail
--
;
if
(
c
==
delim
)
break
;
}
*
read_pos
=
'\0'
;
return
read_pos
-
*
lineptr
;
}
ssize_t
my_getline
(
char
**
lineptr
,
size_t
*
n
,
FILE
*
stream
)
{
return
my_getdelim
(
lineptr
,
n
,
'\n'
,
stream
);
}
/* All the string should be freed manually!! */
/* All the string should be freed manually!! */
int
file_to_vector
(
const
char
*
filename
,
struct
vector
*
v
)
{
int
file_to_vector
(
const
char
*
filename
,
struct
vector
*
v
)
{
if
(
access
(
filename
,
R_OK
)
!=
0
)
if
(
access
(
filename
,
R_OK
)
!=
0
)
...
@@ -468,3 +395,81 @@ int strend(const char *s1, const char *s2) {
...
@@ -468,3 +395,81 @@ int strend(const char *s1, const char *s2) {
size_t
l2
=
strlen
(
s2
);
size_t
l2
=
strlen
(
s2
);
return
strcmp
(
s1
+
l1
-
l2
,
s2
);
return
strcmp
(
s1
+
l1
-
l2
,
s2
);
}
}
/* Original source: https://opensource.apple.com/source/cvs/cvs-19/cvs/lib/getline.c
* License: GPL 2 or later
* Adjusted to match POSIX */
#define MIN_CHUNK 64
ssize_t
__getdelim
(
char
**
lineptr
,
size_t
*
n
,
int
delim
,
FILE
*
stream
)
{
size_t
nchars_avail
;
char
*
read_pos
;
if
(
!
lineptr
||
!
n
||
!
stream
)
{
errno
=
EINVAL
;
return
-
1
;
}
if
(
!*
lineptr
)
{
*
n
=
MIN_CHUNK
;
*
lineptr
=
malloc
(
*
n
);
if
(
!*
lineptr
)
{
errno
=
ENOMEM
;
return
-
1
;
}
}
nchars_avail
=
*
n
;
read_pos
=
*
lineptr
;
while
(
1
)
{
int
save_errno
;
register
int
c
=
getc
(
stream
);
save_errno
=
errno
;
if
(
nchars_avail
<
2
)
{
if
(
*
n
>
MIN_CHUNK
)
*
n
*=
2
;
else
*
n
+=
MIN_CHUNK
;
nchars_avail
=
*
n
+
*
lineptr
-
read_pos
;
*
lineptr
=
realloc
(
*
lineptr
,
*
n
);
if
(
!*
lineptr
)
{
errno
=
ENOMEM
;
return
-
1
;
}
read_pos
=
*
n
-
nchars_avail
+
*
lineptr
;
}
if
(
ferror
(
stream
))
{
errno
=
save_errno
;
return
-
1
;
}
if
(
c
==
EOF
)
{
if
(
read_pos
==
*
lineptr
)
return
-
1
;
else
break
;
}
*
read_pos
++
=
c
;
nchars_avail
--
;
if
(
c
==
delim
)
break
;
}
*
read_pos
=
'\0'
;
return
read_pos
-
*
lineptr
;
}
ssize_t
__getline
(
char
**
lineptr
,
size_t
*
n
,
FILE
*
stream
)
{
return
__getdelim
(
lineptr
,
n
,
'\n'
,
stream
);
}
int
__fsetxattr
(
int
fd
,
const
char
*
name
,
const
void
*
value
,
size_t
size
,
int
flags
)
{
return
(
int
)
syscall
(
__NR_fsetxattr
,
fd
,
name
,
value
,
size
,
flags
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment